niceeval 0.5.3 → 0.6.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.
Files changed (344) hide show
  1. package/INDEX.md +55 -0
  2. package/dist/agents/types.d.ts +317 -0
  3. package/dist/context/types.d.ts +335 -0
  4. package/dist/i18n/core.d.ts +11 -0
  5. package/dist/i18n/en.d.ts +181 -0
  6. package/dist/i18n/index.d.ts +5 -0
  7. package/dist/i18n/zh-CN.d.ts +183 -0
  8. package/dist/o11y/execution-tree.d.ts +103 -0
  9. package/dist/o11y/otlp/parse.d.ts +3 -0
  10. package/dist/o11y/otlp/receiver.d.ts +21 -0
  11. package/dist/o11y/otlp/select.d.ts +22 -0
  12. package/dist/o11y/otlp/turn-otel.d.ts +43 -0
  13. package/dist/o11y/types.d.ts +190 -0
  14. package/dist/report/aggregate.d.ts +57 -0
  15. package/dist/report/aggregate.js +212 -0
  16. package/dist/report/built-ins/cost-pass-rate-comparison.d.ts +1 -0
  17. package/dist/report/built-ins/cost-pass-rate-comparison.js +17 -0
  18. package/dist/report/built-ins/index.d.ts +1 -0
  19. package/dist/report/built-ins/index.js +2 -0
  20. package/dist/report/components.d.ts +178 -0
  21. package/dist/report/components.js +132 -0
  22. package/dist/report/compute.d.ts +106 -0
  23. package/dist/report/compute.js +618 -0
  24. package/dist/report/flag.d.ts +6 -0
  25. package/dist/report/flag.js +8 -0
  26. package/dist/report/format.d.ts +32 -0
  27. package/dist/report/format.js +126 -0
  28. package/dist/report/index.d.ts +19 -0
  29. package/dist/report/index.js +30 -0
  30. package/dist/report/load.d.ts +12 -0
  31. package/dist/report/load.js +56 -0
  32. package/dist/report/locale.d.ts +83 -0
  33. package/dist/report/locale.js +160 -0
  34. package/dist/report/metrics.d.ts +21 -0
  35. package/dist/report/metrics.js +115 -0
  36. package/dist/report/primitives.d.ts +64 -0
  37. package/dist/report/primitives.js +113 -0
  38. package/dist/report/react/AttemptList.d.ts +23 -0
  39. package/dist/report/react/AttemptList.js +20 -0
  40. package/dist/report/react/DeltaTable.d.ts +8 -0
  41. package/dist/report/react/DeltaTable.js +24 -0
  42. package/dist/report/react/EvalList.d.ts +10 -0
  43. package/dist/report/react/EvalList.js +0 -0
  44. package/dist/report/react/ExperimentList.d.ts +10 -0
  45. package/dist/report/react/ExperimentList.js +15 -0
  46. package/dist/report/react/GroupSummary.d.ts +8 -0
  47. package/dist/report/react/GroupSummary.js +8 -0
  48. package/dist/report/react/MetricBars.d.ts +10 -0
  49. package/dist/report/react/MetricBars.js +48 -0
  50. package/dist/report/react/MetricLine.d.ts +9 -0
  51. package/dist/report/react/MetricLine.js +68 -0
  52. package/dist/report/react/MetricMatrix.d.ts +10 -0
  53. package/dist/report/react/MetricMatrix.js +23 -0
  54. package/dist/report/react/MetricScatter.d.ts +9 -0
  55. package/dist/report/react/MetricScatter.js +100 -0
  56. package/dist/report/react/MetricTable.d.ts +11 -0
  57. package/dist/report/react/MetricTable.js +26 -0
  58. package/dist/report/react/RunOverview.d.ts +8 -0
  59. package/dist/report/react/RunOverview.js +12 -0
  60. package/dist/report/react/Scoreboard.d.ts +8 -0
  61. package/dist/report/react/Scoreboard.js +26 -0
  62. package/dist/report/react/cell.d.ts +9 -0
  63. package/dist/report/react/cell.js +9 -0
  64. package/dist/report/react/chart-math.d.ts +14 -0
  65. package/dist/report/react/chart-math.js +68 -0
  66. package/dist/report/react/colors.d.ts +14 -0
  67. package/dist/report/react/colors.js +45 -0
  68. package/dist/report/react/fixtures.d.ts +19 -0
  69. package/dist/report/react/fixtures.js +393 -0
  70. package/dist/report/react/format.d.ts +3 -0
  71. package/dist/report/react/format.js +7 -0
  72. package/dist/report/react/index.d.ts +6 -0
  73. package/dist/report/react/index.js +14 -0
  74. package/dist/report/report.d.ts +24 -0
  75. package/dist/report/report.js +49 -0
  76. package/dist/report/text/faces.d.ts +29 -0
  77. package/dist/report/text/faces.js +503 -0
  78. package/dist/report/text/layout.d.ts +75 -0
  79. package/dist/report/text/layout.js +173 -0
  80. package/dist/report/text/plot.d.ts +37 -0
  81. package/dist/report/text/plot.js +81 -0
  82. package/dist/report/text/table.d.ts +8 -0
  83. package/dist/report/text/table.js +86 -0
  84. package/dist/report/tree.d.ts +99 -0
  85. package/dist/report/tree.js +228 -0
  86. package/dist/report/types.d.ts +420 -0
  87. package/dist/report/types.js +4 -0
  88. package/dist/report/web.d.ts +15 -0
  89. package/dist/report/web.js +37 -0
  90. package/dist/results/annotated-source.d.ts +61 -0
  91. package/dist/results/attempt-evidence.d.ts +69 -0
  92. package/dist/results/attempt-source.d.ts +15 -0
  93. package/dist/results/locator.d.ts +75 -0
  94. package/dist/results/locator.js +0 -0
  95. package/dist/results/select.d.ts +45 -0
  96. package/dist/results/select.js +230 -0
  97. package/dist/results/source-hash.d.ts +9 -0
  98. package/dist/results/types.d.ts +204 -0
  99. package/dist/runner/eval-source.d.ts +22 -0
  100. package/dist/runner/fingerprint.d.ts +23 -0
  101. package/dist/runner/types.d.ts +332 -0
  102. package/dist/sandbox/docker-stream.d.ts +24 -0
  103. package/dist/sandbox/docker.d.ts +84 -0
  104. package/dist/sandbox/e2b.d.ts +31 -0
  105. package/dist/sandbox/errors.d.ts +4 -0
  106. package/dist/sandbox/local-files.d.ts +6 -0
  107. package/dist/sandbox/paths.d.ts +4 -0
  108. package/dist/sandbox/registry.d.ts +13 -0
  109. package/dist/sandbox/resolve.d.ts +40 -0
  110. package/dist/sandbox/retry.d.ts +10 -0
  111. package/dist/sandbox/shell.d.ts +11 -0
  112. package/dist/sandbox/source-files.d.ts +13 -0
  113. package/dist/sandbox/types.d.ts +203 -0
  114. package/dist/sandbox/vercel.d.ts +37 -0
  115. package/dist/scoring/types.d.ts +70 -0
  116. package/dist/shared/aggregate.d.ts +29 -0
  117. package/dist/shared/aggregate.js +55 -0
  118. package/dist/shared/types.d.ts +27 -0
  119. package/dist/shared/verdict.d.ts +27 -0
  120. package/dist/shared/verdict.js +34 -0
  121. package/dist/tty-line.d.ts +6 -0
  122. package/dist/types.d.ts +7 -0
  123. package/dist/util.d.ts +22 -0
  124. package/docs-site/zh/concepts/adapter.mdx +9 -4
  125. package/docs-site/zh/concepts/assert.mdx +8 -8
  126. package/docs-site/zh/concepts/evals.mdx +5 -5
  127. package/docs-site/zh/concepts/experiment.mdx +3 -1
  128. package/docs-site/zh/concepts/judge.mdx +9 -9
  129. package/docs-site/zh/concepts/overview.mdx +2 -2
  130. package/docs-site/zh/concepts/tier.mdx +6 -6
  131. package/docs-site/zh/example/claude-code-codex-plugin.mdx +9 -5
  132. package/docs-site/zh/example/claude-code-codex-skill.mdx +12 -7
  133. package/docs-site/zh/guides/agent-feedback-loop.mdx +235 -78
  134. package/docs-site/zh/guides/connect-otel.mdx +3 -3
  135. package/docs-site/zh/guides/connect-your-agent.mdx +2 -2
  136. package/docs-site/zh/guides/custom-reports.mdx +196 -36
  137. package/docs-site/zh/guides/experiments.mdx +7 -0
  138. package/docs-site/zh/guides/fixtures.mdx +1 -1
  139. package/docs-site/zh/guides/official-adapters.mdx +31 -9
  140. package/docs-site/zh/guides/publish-report.mdx +4 -4
  141. package/docs-site/zh/guides/report-components.mdx +194 -55
  142. package/docs-site/zh/guides/reporters.mdx +2 -2
  143. package/docs-site/zh/guides/results-data.mdx +35 -34
  144. package/docs-site/zh/guides/runner.mdx +2 -2
  145. package/docs-site/zh/guides/sandbox-agent.mdx +10 -5
  146. package/docs-site/zh/guides/sandbox-providers.mdx +102 -0
  147. package/docs-site/zh/guides/viewing-results.mdx +199 -79
  148. package/docs-site/zh/guides/write-experiment.mdx +23 -1
  149. package/docs-site/zh/guides/write-send.mdx +2 -2
  150. package/docs-site/zh/index.mdx +4 -3
  151. package/docs-site/zh/introduction.mdx +2 -1
  152. package/docs-site/zh/quickstart.mdx +5 -3
  153. package/docs-site/zh/reference/builtin-agents.mdx +38 -13
  154. package/docs-site/zh/reference/capabilities.mdx +1 -1
  155. package/docs-site/zh/reference/cli.mdx +36 -13
  156. package/docs-site/zh/reference/define-agent.mdx +24 -12
  157. package/docs-site/zh/reference/define-config.mdx +1 -1
  158. package/docs-site/zh/reference/define-eval.mdx +3 -3
  159. package/docs-site/zh/reference/events.mdx +7 -1
  160. package/docs-site/zh/reference/expect.mdx +3 -3
  161. package/package.json +10 -6
  162. package/src/agents/bub.ts +134 -43
  163. package/src/agents/claude-code.test.ts +152 -0
  164. package/src/agents/claude-code.ts +127 -13
  165. package/src/agents/codex.test.ts +192 -0
  166. package/src/agents/codex.ts +151 -12
  167. package/src/agents/index.ts +11 -3
  168. package/src/agents/manifest.ts +41 -0
  169. package/src/agents/plugin-config.test.ts +94 -0
  170. package/src/agents/shared.ts +33 -2
  171. package/src/agents/skills.test.ts +214 -0
  172. package/src/agents/skills.ts +304 -0
  173. package/src/agents/streaming.ts +5 -5
  174. package/src/agents/types.ts +62 -2
  175. package/src/cli.ts +74 -47
  176. package/src/context/context.test.ts +20 -2
  177. package/src/context/context.ts +3 -0
  178. package/src/context/control-flow.ts +1 -1
  179. package/src/context/session.test.ts +92 -1
  180. package/src/context/session.ts +26 -1
  181. package/src/context/types.ts +4 -4
  182. package/src/define.test.ts +82 -0
  183. package/src/define.ts +72 -11
  184. package/src/expect/index.ts +5 -5
  185. package/src/i18n/en.ts +36 -15
  186. package/src/i18n/zh-CN.ts +39 -21
  187. package/src/index.ts +1 -1
  188. package/src/o11y/execution-tree.test.ts +452 -0
  189. package/src/o11y/execution-tree.ts +367 -0
  190. package/src/o11y/otlp/receiver.ts +1 -1
  191. package/src/o11y/otlp/select.ts +7 -3
  192. package/src/o11y/parsers/claude-code.test.ts +175 -0
  193. package/src/o11y/parsers/claude-code.ts +32 -0
  194. package/src/o11y/types.ts +6 -1
  195. package/src/report/aggregate.ts +26 -20
  196. package/src/report/built-in-user-parity.test.tsx +643 -0
  197. package/src/report/built-ins/cost-pass-rate-comparison.tsx +23 -0
  198. package/src/report/built-ins/index.ts +2 -0
  199. package/src/report/components.tsx +223 -50
  200. package/src/report/compute.ts +358 -53
  201. package/src/report/dual-render.test.tsx +1125 -0
  202. package/src/report/flag.ts +1 -1
  203. package/src/report/format.ts +50 -2
  204. package/src/report/index.ts +48 -14
  205. package/src/report/load.ts +1 -1
  206. package/src/report/locale.ts +206 -0
  207. package/src/report/metrics.ts +39 -15
  208. package/src/report/primitives.tsx +100 -2
  209. package/src/report/react/AttemptList.tsx +115 -0
  210. package/src/report/react/DeltaTable.tsx +9 -6
  211. package/src/report/react/EvalList.tsx +0 -0
  212. package/src/report/react/ExperimentList.tsx +108 -0
  213. package/src/report/react/GroupSummary.tsx +66 -0
  214. package/src/report/react/MetricBars.tsx +24 -13
  215. package/src/report/react/MetricLine.tsx +21 -21
  216. package/src/report/react/MetricMatrix.tsx +8 -4
  217. package/src/report/react/MetricScatter.tsx +136 -96
  218. package/src/report/react/MetricTable.tsx +115 -15
  219. package/src/report/react/RunOverview.tsx +48 -26
  220. package/src/report/react/Scoreboard.tsx +15 -7
  221. package/src/report/react/cell.tsx +18 -9
  222. package/src/{view/app/lib/chart.ts → report/react/chart-math.ts} +2 -6
  223. package/src/report/react/colors.ts +24 -15
  224. package/src/report/react/enhance.js +129 -0
  225. package/src/report/react/fixtures.ts +163 -34
  226. package/src/report/react/format.ts +1 -1
  227. package/src/report/react/index.tsx +22 -6
  228. package/src/report/react/render.test.tsx +164 -31
  229. package/src/report/react/styles.css +405 -213
  230. package/src/report/report.test.ts +403 -94
  231. package/src/report/report.ts +29 -11
  232. package/src/report/text/faces.ts +303 -95
  233. package/src/report/text/layout.ts +76 -11
  234. package/src/report/text/table.ts +98 -0
  235. package/src/report/tree.ts +103 -20
  236. package/src/report/types.ts +196 -25
  237. package/src/report/web.ts +46 -19
  238. package/src/results/annotated-source.test.ts +146 -0
  239. package/src/results/annotated-source.ts +128 -0
  240. package/src/results/attempt-evidence.test.ts +158 -0
  241. package/src/results/attempt-evidence.ts +158 -0
  242. package/src/results/attempt-source.ts +48 -0
  243. package/src/results/copy.ts +154 -139
  244. package/src/results/format.ts +54 -47
  245. package/src/results/host-equivalence.test.ts +527 -0
  246. package/src/results/index.ts +56 -14
  247. package/src/results/locator.test.ts +198 -0
  248. package/src/results/locator.ts +0 -0
  249. package/src/results/open.ts +392 -175
  250. package/src/results/results.test.ts +943 -494
  251. package/src/results/select.ts +129 -23
  252. package/src/results/skipped-notice.ts +0 -0
  253. package/src/results/source-hash.ts +28 -0
  254. package/src/results/types.ts +98 -62
  255. package/src/results/writer.ts +304 -176
  256. package/src/runner/attempt.test.ts +170 -0
  257. package/src/runner/attempt.ts +97 -15
  258. package/src/runner/discover.test.ts +65 -0
  259. package/src/runner/discover.ts +6 -2
  260. package/src/runner/eval-source.test.ts +121 -0
  261. package/src/runner/eval-source.ts +45 -0
  262. package/src/runner/fingerprint.ts +54 -1
  263. package/src/runner/remote-sandbox.ts +1 -1
  264. package/src/runner/report.test.ts +6 -8
  265. package/src/runner/report.ts +5 -4
  266. package/src/runner/reporters/artifacts.ts +27 -41
  267. package/src/runner/reporters/braintrust.test.ts +3 -3
  268. package/src/runner/reporters/braintrust.ts +1 -1
  269. package/src/runner/reporters/console.ts +6 -6
  270. package/src/runner/reporters/json.ts +4 -4
  271. package/src/runner/reporters/live.test.ts +56 -0
  272. package/src/runner/reporters/live.ts +36 -10
  273. package/src/runner/reporters/quiet.test.ts +66 -0
  274. package/src/runner/reporters/quiet.ts +49 -0
  275. package/src/runner/reporters/shared.ts +5 -5
  276. package/src/runner/reporters/table.ts +17 -17
  277. package/src/runner/run.ts +61 -102
  278. package/src/runner/types.ts +43 -32
  279. package/src/sandbox/checkpoint.ts +1 -1
  280. package/src/sandbox/docker.ts +15 -2
  281. package/src/sandbox/e2b.ts +11 -5
  282. package/src/sandbox/errors.ts +13 -0
  283. package/src/sandbox/index.ts +3 -3
  284. package/src/sandbox/local-files.ts +1 -1
  285. package/src/sandbox/registry.ts +6 -5
  286. package/src/sandbox/resolve.ts +38 -23
  287. package/src/sandbox/retry.test.ts +68 -0
  288. package/src/sandbox/retry.ts +44 -0
  289. package/src/sandbox/types.ts +69 -28
  290. package/src/sandbox/vercel.ts +17 -3
  291. package/src/scoring/collector.ts +3 -3
  292. package/src/scoring/judge.ts +2 -2
  293. package/src/scoring/scoped.ts +13 -1
  294. package/src/scoring/types.ts +7 -7
  295. package/src/scoring/verdict.ts +4 -4
  296. package/src/shared/aggregate.ts +23 -3
  297. package/src/shared/types.ts +2 -2
  298. package/src/shared/{outcome.ts → verdict.ts} +15 -15
  299. package/src/show/compose.ts +12 -132
  300. package/src/show/index.ts +125 -94
  301. package/src/show/render.ts +660 -160
  302. package/src/show/show.test.ts +472 -253
  303. package/src/source-loc.ts +1 -1
  304. package/src/tty-line.ts +32 -0
  305. package/src/types.ts +2 -2
  306. package/src/util.test.ts +21 -1
  307. package/src/util.ts +5 -1
  308. package/src/view/app/App.tsx +33 -198
  309. package/src/view/app/components/AttemptModal.tsx +6 -6
  310. package/src/view/app/components/CodeView.tsx +2 -2
  311. package/src/view/app/components/CopyControls.tsx +32 -36
  312. package/src/view/app/components/SkippedRunsBanner.tsx +140 -0
  313. package/src/view/app/components/ui/badge.tsx +1 -1
  314. package/src/view/app/components/ui/dialog.tsx +2 -2
  315. package/src/view/app/i18n.ts +40 -31
  316. package/src/view/app/lib/artifact-url.ts +1 -1
  317. package/src/view/app/lib/attempt-route.test.ts +37 -47
  318. package/src/view/app/lib/attempt-route.ts +26 -26
  319. package/src/view/app/lib/rows.ts +9 -112
  320. package/src/view/app/lib/verdict.ts +25 -0
  321. package/src/view/app/main.tsx +9 -12
  322. package/src/view/app/pages/RunsPage.tsx +4 -4
  323. package/src/view/app/pages/TracesPage.tsx +3 -3
  324. package/src/view/app/shared.ts +0 -1
  325. package/src/view/app/types.ts +6 -51
  326. package/src/view/artifact-serving.test.ts +136 -0
  327. package/src/view/client-dist/app.css +1 -1
  328. package/src/view/client-dist/app.js +21 -21
  329. package/src/view/data.test.ts +214 -143
  330. package/src/view/data.ts +166 -120
  331. package/src/view/index.ts +23 -11
  332. package/src/view/server.ts +52 -17
  333. package/src/view/shared/types.ts +22 -31
  334. package/src/view/styles.css +117 -327
  335. package/src/view/view-report.test.ts +146 -98
  336. package/docs-site/zh/guides/sandbox-backends.mdx +0 -75
  337. package/src/report/default-report.tsx +0 -222
  338. package/src/report/dual-face.test.tsx +0 -527
  339. package/src/report/react/CaseList.tsx +0 -70
  340. package/src/view/app/components/CostScoreChart.tsx +0 -147
  341. package/src/view/app/components/ExperimentTable.tsx +0 -284
  342. package/src/view/app/components/GroupSelector.tsx +0 -61
  343. package/src/view/app/components/primitives.tsx +0 -43
  344. package/src/view/app/lib/outcome.ts +0 -82
@@ -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,4 @@
1
+ /** 目前只区分"限流,值得退避重试"和"其它,原样抛出"。 */
2
+ export type SandboxProvisionErrorKind = "rate_limit" | "unknown";
3
+ /** 按 kind 判断是否该重试;模板不存在、凭据缺失等归入 unknown,第一次就抛,重试没有意义。 */
4
+ export declare function isRetryableProvisionError(kind: SandboxProvisionErrorKind): boolean;
@@ -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>;
@@ -0,0 +1,203 @@
1
+ import type { AgentSetup, AgentTeardown } from "../agents/types.ts";
2
+ export interface CommandResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ exitCode: number;
6
+ }
7
+ export interface SandboxFile {
8
+ path: string;
9
+ content: string | Buffer;
10
+ }
11
+ /** 一个源码文件:相对工作区根的路径 + 文本内容。readSourceFiles 的返回元素。 */
12
+ export interface SourceFile {
13
+ path: string;
14
+ content: string;
15
+ }
16
+ /**
17
+ * readSourceFiles 的返回值:仍是一个 SourceFile 数组(.filter/.some/.map 照用),
18
+ * 额外挂上整体匹配 / 按文件匹配的便利方法,省掉 eval 目录里手写的 source-helpers。
19
+ */
20
+ export interface SourceFiles extends ReadonlyArray<SourceFile> {
21
+ /** 全部文件内容拼接(每段前带 `// path` 注释),用于整体 regex。 */
22
+ text(): string;
23
+ /** 同 text() 但先剥注释,只看真实代码。 */
24
+ code(): string;
25
+ /** 第一个内容命中 pattern 的文件。 */
26
+ fileMatching(pattern: RegExp): SourceFile | undefined;
27
+ /** 第一个内容命中全部 patterns 的文件(同文件共现,per-file 而非拼接源码)。 */
28
+ fileMatchingAll(patterns: RegExp[]): SourceFile | undefined;
29
+ /** 是否存在路径命中 pattern 的文件。 */
30
+ hasPath(pattern: RegExp): boolean;
31
+ }
32
+ /** readSourceFiles 的可选项;不传则用一套合理默认。 */
33
+ export interface ReadSourceFilesOptions {
34
+ /** 文件扩展名(不带点)。默认 ts/tsx/js/jsx。 */
35
+ extensions?: string[];
36
+ /** 按目录名(任意深度)剪枝。默认 .git/.next/node_modules/dist/build/coverage。 */
37
+ ignoreDirs?: string[];
38
+ /** 按文件 basename 忽略。默认 EVAL.ts/PROMPT.md。 */
39
+ ignoreFiles?: string[];
40
+ }
41
+ /** 内置 provider 名;不出现在 `sandbox` 字段的类型里(spec 用各自的 `provider` 判别字段区分)。 */
42
+ export type SandboxProvider = "docker" | "vercel" | "e2b";
43
+ /** 镜像/模板里的 Node 运行时版本。 */
44
+ export type SandboxRuntime = "node20" | "node24";
45
+ /**
46
+ * SandboxSpec 四个变体共有的沙箱生命周期钩子挂载点:`.setup(fn)` / `.teardown(fn)` 链式方法,
47
+ * 由 `dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()` / `defineSandbox()` 产出的对象上
48
+ * 直接可调。
49
+ *
50
+ * **语义**:环境预置层,俗称「动态镜像层」——本想直接烘进镜像/快照/模板,但内容要按实验
51
+ * (`ctx.flags` / `ctx.experimentId`)动态变化的东西:装某个实验专属的二进制、预热缓存、
52
+ * 写运行期才知道内容的 hook 文件、按 `ctx.experimentId` 载入/回存跨 attempt 的状态。
53
+ *
54
+ * **与另外两层 setup 的分工**(三者都在同一个沙箱生命周期里,各管一层):
55
+ * · `sandbox.setup`(这里)—— 环境层,不知道具体跑哪个 eval / 接哪个 agent;
56
+ * · `eval.setup` —— 任务层,准备这次 eval 的素材(如 `npm install` 起始项目依赖);
57
+ * · `agent.setup` —— 协议层,接入被测 agent(装 CLI、写鉴权 / 模型配置)。
58
+ *
59
+ * **执行顺序**:沙箱就绪 → `sandbox.setup` 钩子 → workspace 上传 / git 基线 / `eval.setup` →
60
+ * `agent.setup` → `agent.tracing.configure` → 逐轮 `send`。`sandbox.setup` 特意排在 git
61
+ * 基线之前——它的改动会被提交进基线,不会被误算进 agent 产出的 diff。收尾按 LIFO:
62
+ * agent 级 cleanup / `agent.teardown` 先跑,`sandbox.teardown` 钩子最后跑(沙箱销毁前)。
63
+ *
64
+ * **多钩子**:`.setup(a).setup(b)` 按追加顺序依次执行(a 先 b 后);`.teardown(x).teardown(y)`
65
+ * 按追加的**逆序**执行(y 先 x 后)。每次调用都返回一个新 spec(不改变原对象),可继续链式。
66
+ *
67
+ * **失败语义**:`setup` 钩子抛错按执行错误计——与 `eval.setup` / `agent.setup` 抛错走同一条
68
+ * 路径,不新增错误分类;但不阻断该 attempt 已进入的收尾(已跑过的 setup 返回的 cleanup、
69
+ * `teardown` 钩子仍会在 finally 里跑)。`teardown` 钩子报错只作诊断(吞掉 / 记 log),不改变
70
+ * 已产出的结果——与 `agent.teardown` 现状一致。
71
+ */
72
+ export interface SandboxHooks<Self> {
73
+ /** 已挂载的 setup 钩子,按追加顺序保存(内部读取,一般用不到)。 */
74
+ readonly setupHooks?: readonly AgentSetup[];
75
+ /** 已挂载的 teardown 钩子,按追加顺序保存,执行时逆序(内部读取,一般用不到)。 */
76
+ readonly teardownHooks?: readonly AgentTeardown[];
77
+ /** 追加一个沙箱级 setup 钩子,返回新 spec;详细契约见 {@link SandboxHooks}。 */
78
+ setup(fn: AgentSetup): Self;
79
+ /** 追加一个沙箱级 teardown 钩子,返回新 spec;详细契约见 {@link SandboxHooks}。 */
80
+ teardown(fn: AgentTeardown): Self;
81
+ }
82
+ /**
83
+ * Sandbox 的「数据结构」定义 —— 与 agent 一样可带参数(见 docs/feature/sandbox/library.md)。
84
+ * 必须用工厂函数构造(`dockerSandbox()` / `vercelSandbox()` / `e2bSandbox()` / `defineSandbox()`),
85
+ * 放进 config / experiment 的 `sandbox` 字段 —— 字段类型只接受这个数据结构,不接受裸字符串。
86
+ * 各 provider 的参数互不相同 —— 这是个按 `provider` 区分的可辨识联合(discriminated union)。
87
+ * 四个变体都带 {@link SandboxHooks} 的 `.setup()` / `.teardown()` 链式方法。
88
+ */
89
+ export interface DockerSandboxSpec extends SandboxHooks<DockerSandboxSpec> {
90
+ readonly provider: "docker";
91
+ /** 覆盖默认镜像;默认按 runtime 选 `node:*-slim`。预制模板:传烘焙好 agent CLI 的镜像名。 */
92
+ readonly image?: string;
93
+ readonly runtime?: SandboxRuntime;
94
+ }
95
+ export interface VercelSandboxSpec extends SandboxHooks<VercelSandboxSpec> {
96
+ readonly provider: "vercel";
97
+ /** 从已有快照起 microVM。预制模板:烘焙好 agent CLI 的 snapshotId。 */
98
+ readonly snapshotId?: string;
99
+ readonly runtime?: SandboxRuntime;
100
+ }
101
+ export interface E2BSandboxSpec extends SandboxHooks<E2BSandboxSpec> {
102
+ readonly provider: "e2b";
103
+ /** e2b 模板名/ID。预制模板:烘焙好 agent CLI 的模板(如 `"niceeval-agents"`)。省略用 e2b 默认 `"base"`。 */
104
+ readonly template?: string;
105
+ /** 仅作记录;e2b 的 node 版本由模板决定,不在创建时选。 */
106
+ readonly runtime?: SandboxRuntime;
107
+ }
108
+ /**
109
+ * 用户自定义 provider:`create` 直接产出一个 `Sandbox` 实例,不经 resolve.ts 的内置 provider switch。
110
+ * 用 `defineSandbox()` 构造(见 src/define.ts)。`provider` 只用于展示 / 日志,不参与分发。
111
+ */
112
+ export interface CustomSandboxSpec extends SandboxHooks<CustomSandboxSpec> {
113
+ readonly provider: string;
114
+ readonly runtime?: SandboxRuntime;
115
+ readonly recommendedConcurrency?: number;
116
+ readonly create: (opts: {
117
+ timeout?: number;
118
+ runtime?: SandboxRuntime;
119
+ }) => Promise<Sandbox>;
120
+ }
121
+ export type SandboxSpec = DockerSandboxSpec | VercelSandboxSpec | E2BSandboxSpec | CustomSandboxSpec;
122
+ /** config / experiment 的 `sandbox` 字段:必须是工厂函数产出的 spec 数据结构;沙箱型 agent 不能省略。 */
123
+ export type SandboxOption = SandboxSpec;
124
+ export interface CommandOptions {
125
+ /** 追加/覆盖本命令的环境变量(与沙箱默认环境叠加,不清空默认值;各 provider 会保留自己固定的 `PATH` 等变量,不保证能被这里覆盖)。 */
126
+ env?: Record<string, string>;
127
+ /** 本命令的工作目录;省略时落到 `Sandbox.workdir`。相对路径按 workdir 解析,绝对路径原样使用。 */
128
+ cwd?: string;
129
+ /**
130
+ * 把本命令的输出也送进沙箱的「原生日志流」(于是 `docker logs` / Docker UI 的 Logs
131
+ * 标签页能实时看到它)。给 agent 命令(codex exec / bub run / claude)开它,就能在容器
132
+ * 日志里看到 agent 的【原始输出】。provider 各自实现(docker:tee 到 PID1 tail 的文件;
133
+ * 不支持的 provider 忽略)—— 日志怎么浮现是 provider 的事,adapter 只声明意图。
134
+ */
135
+ stream?: boolean;
136
+ /**
137
+ * 以 root 跑本命令。默认 `false` —— 命令以沙箱的标准**非 root** 用户跑(agent 的自然环境)。
138
+ * 给 setup 阶段装系统依赖用(`apt-get install …`、`pip install --break-system-packages …`)。
139
+ *
140
+ * 语义跨 provider 一致:"本命令以 root 跑,否则以标准非 root 用户跑"。各 provider 映射到自己的原生机制
141
+ * (docker:`exec --user root`;E2B:`{ user: "root" }`;Vercel:`{ sudo: true }`;Daytona:`{ user }`)。
142
+ * 本就全程 root 的 provider(如 Modal)视作 no-op;完全无法提权的 provider 可不支持(抛错)—— 但**默认值与
143
+ * 语义保持一致**,不因 provider 而变。
144
+ */
145
+ root?: boolean;
146
+ }
147
+ export interface Sandbox {
148
+ /** 沙箱内项目/工作区根目录的绝对路径(agent 命令的默认 cwd,也是 git baseline 提交的位置)。各方法的相对路径都以此为基准解析,省略 `cwd`/`targetDir` 时也落到这里。 */
149
+ readonly workdir: string;
150
+ /**
151
+ * 执行单个命令,`args` 作为独立 argv 传递、不经 shell 解释(无 `&&`、管道、通配符展开)。
152
+ * 只想跑一个可执行文件、参数来自外部输入、担心注入时优先用它。
153
+ */
154
+ runCommand(cmd: string, args?: string[], opts?: CommandOptions): Promise<CommandResult>;
155
+ /**
156
+ * 执行一整段脚本,经 shell(bash)解释,支持 `&&`、管道、`$()`、重定向等。
157
+ * 需要拼多条命令或做条件判断时用它。
158
+ */
159
+ runShell(script: string, opts?: CommandOptions): Promise<CommandResult>;
160
+ /** 读取沙箱内文件的文本内容(UTF-8)。文件不存在时抛错,不返回空字符串——需要容错请自行 `.catch()`。 */
161
+ readFile(path: string): Promise<string>;
162
+ /** 检查沙箱内路径是否存在。跨 provider 语义不完全一致:仅保证对普通文件可靠,对目录路径的行为不同 provider 不保证一致。 */
163
+ fileExists(path: string): Promise<boolean>;
164
+ /**
165
+ * 一次 shell 往返读全部源码文件(按扩展名收、按目录/文件名忽略)。
166
+ * 取代每个 eval 目录里手写的 find + 逐文件 readFile。
167
+ */
168
+ readSourceFiles(opts?: ReadSourceFilesOptions): Promise<SourceFiles>;
169
+ /** 写入若干文本文件(内容已在内存里的字符串);是 `uploadFiles` 的文本特化,省略 `targetDir` 落到 workdir。 */
170
+ writeFiles(files: Record<string, string>, targetDir?: string): Promise<void>;
171
+ /** 批量写入若干文件,内容可以是文本或二进制 Buffer;省略 `targetDir` 落到 workdir。 */
172
+ uploadFiles(files: SandboxFile[], targetDir?: string): Promise<void>;
173
+ /** 把本地磁盘上的一个目录整体上传进沙箱(递归读取本地文件后按 `uploadFiles` 写入);`opts.ignore` 是排除规则,省略 `targetDir` 落到 workdir。 */
174
+ uploadDirectory(localDir: string, targetDir?: string, opts?: {
175
+ ignore?: string[];
176
+ }): Promise<void>;
177
+ /** 销毁沙箱占用的计算资源(容器/microVM)。调用后沙箱不可再用;是否可安全重复调用因 provider 而异,不要依赖这一点。 */
178
+ stop(): Promise<void>;
179
+ /** 本沙箱的稳定标识(各 provider 原生 ID,如 Docker 容器 ID 前缀);用于跨调用关联同一沙箱的会话状态,也用于日志展示。 */
180
+ readonly sandboxId: string;
181
+ /**
182
+ * 本地 OTLP 接收器的目标 host。
183
+ * - `string`:沙箱内可通过该 hostname 回连宿主 OTLP 端口(如 docker 的 `host.docker.internal`)。
184
+ * - `null`:沙箱运行在远程云端(如 e2b/vercel),无法访问宿主本地端口 → 跳过 tracing。
185
+ * 可通过环境变量 `NICEEVAL_OTLP_HOST` 强制覆盖(如配置 tunnel 时)。
186
+ */
187
+ readonly otlpHost: string | null;
188
+ /**
189
+ * 可选:把一行写进容器的「主日志」(PID1 在 tail 它)——于是 `docker logs` /
190
+ * Docker UI 的 Logs 标签页能实时看到 agent 逐轮活动。docker provider 实现,其它可省略。
191
+ */
192
+ appendLog?(line: string): Promise<void>;
193
+ /**
194
+ * 从沙箱内任意路径读取文件,返回二进制 Buffer。
195
+ * 对应各 provider:Docker getArchive / Vercel readFileToBuffer / e2b files.read(bytes) / …
196
+ */
197
+ downloadFile(path: string): Promise<Buffer>;
198
+ /**
199
+ * 向沙箱内任意路径写入文件(二进制)。
200
+ * 对应各 provider:Docker putArchive / Vercel fs.writeFile(Buffer) / e2b files.write / …
201
+ */
202
+ uploadFile(path: string, content: Buffer): Promise<void>;
203
+ }
@@ -0,0 +1,37 @@
1
+ import type { Sandbox, CommandResult, CommandOptions, SandboxFile, SourceFiles, ReadSourceFilesOptions } from "../types.ts";
2
+ import type { SandboxProvisionErrorKind } from "./errors.ts";
3
+ /**
4
+ * vercel SDK 对单次 fetch 的 429 已有内部重试(见 @vercel/sandbox 的 with-retry.js,
5
+ * 5 次指数退避);这里再分类是为了给 create() 整体重试兜底——耗尽内部重试后仍返回 429
6
+ * 响应的 APIError,或 create() 轮询 session 状态过程里撞到的限流,都会走到这里。
7
+ */
8
+ export declare function classifyProvisionError(e: unknown): SandboxProvisionErrorKind;
9
+ export declare class VercelSandbox implements Sandbox {
10
+ readonly workdir = "/vercel/sandbox";
11
+ readonly otlpHost: null;
12
+ private vsb;
13
+ private commandTimeoutMs;
14
+ private sessionCreatedAt;
15
+ private runtime;
16
+ readonly sandboxId: string;
17
+ private constructor();
18
+ static create(opts?: {
19
+ timeout?: number;
20
+ runtime?: "node20" | "node24";
21
+ snapshotId?: string;
22
+ }): Promise<VercelSandbox>;
23
+ private rotateIfNeeded;
24
+ runCommand(cmd: string, args?: string[], opts?: CommandOptions): Promise<CommandResult>;
25
+ runShell(script: string, opts?: CommandOptions): Promise<CommandResult>;
26
+ readFile(path: string): Promise<string>;
27
+ fileExists(path: string): Promise<boolean>;
28
+ readSourceFiles(opts?: ReadSourceFilesOptions): Promise<SourceFiles>;
29
+ writeFiles(files: Record<string, string>, targetDir?: string): Promise<void>;
30
+ uploadFiles(files: SandboxFile[], targetDir?: string): Promise<void>;
31
+ uploadDirectory(localDir: string, targetDir?: string, opts?: {
32
+ ignore?: string[];
33
+ }): Promise<void>;
34
+ stop(): Promise<void>;
35
+ downloadFile(path: string): Promise<Buffer>;
36
+ uploadFile(path: string, content: Buffer): Promise<void>;
37
+ }
@@ -0,0 +1,70 @@
1
+ import type { Severity, SourceLoc } from "../shared/types.ts";
2
+ import type { DerivedFacts, StreamEvent, Usage } from "../o11y/types.ts";
3
+ /** 值断言(expect 匹配器)。纯函数 score + 可链式改严重度 / 阈值。 */
4
+ export interface ValueAssertion {
5
+ readonly name: string;
6
+ readonly severity: Severity;
7
+ readonly threshold?: number;
8
+ score(value: unknown): number | Promise<number>;
9
+ /** 转成硬门槛断言:未达阈值(省略 threshold 则按 score > 0 判定)整条 eval 判为 failed。返回新实例,不改原对象。 */
10
+ gate(threshold?: number): ValueAssertion;
11
+ /**
12
+ * 转成软阈值断言:未达 threshold 时该条记为 failed,但默认不拖累整条 eval 的 verdict;
13
+ * `--strict` 运行下,软阈值失败也会把整条 eval 的 verdict 计为 failed。返回新实例,不改原对象。
14
+ */
15
+ atLeast(threshold: number): ValueAssertion;
16
+ }
17
+ /** 收集到 collector 里的一条断言记录(评估前)。 */
18
+ export interface AssertionSpec {
19
+ name: string;
20
+ severity: Severity;
21
+ threshold?: number;
22
+ /** 延迟评估:final 时拿到完整运行结果再算分。 */
23
+ evaluate(ctx: ScoringContext): Promise<number> | number;
24
+ }
25
+ /** 断言评估完的结果(进判定 / 报告)。 */
26
+ export interface AssertionResult {
27
+ name: string;
28
+ severity: Severity;
29
+ threshold?: number;
30
+ score: number;
31
+ passed: boolean;
32
+ detail?: string;
33
+ /** 这条分数是看着什么材料算出来的(judge 收到的输入,或 t.check 失败时实际被检查的值)。view 展开排查「为什么是这个分」,默认不展示。 */
34
+ evidence?: string;
35
+ /** 所属分组(t.group 标题)。纯报告用,不影响 passed/score。 */
36
+ group?: string;
37
+ /** 断言在 eval 源码里的调用点(栈回溯抠出);view 把判定叠回这一行。 */
38
+ loc?: SourceLoc;
39
+ }
40
+ /** eval 作者拿到的可链式句柄(t.judge.autoevals.closedQA(...).atLeast(0.7))。 */
41
+ export interface AssertionHandle {
42
+ atLeast(threshold: number): AssertionHandle;
43
+ gate(threshold?: number): AssertionHandle;
44
+ }
45
+ /** scoped / judge 断言在 final 评估时拿到的运行结果。 */
46
+ export interface ScoringContext {
47
+ readonly events: readonly StreamEvent[];
48
+ readonly facts: DerivedFacts;
49
+ readonly diff: DiffData;
50
+ readonly scripts: Record<string, ScriptResult>;
51
+ readonly usage: Usage;
52
+ readonly status: "completed" | "failed" | "waiting";
53
+ /** 读沙箱里某文件的最终内容(judge / file 断言用)。 */
54
+ readFile(path: string): Promise<string | undefined>;
55
+ }
56
+ export interface ScriptResult {
57
+ success: boolean;
58
+ output: string;
59
+ }
60
+ export interface DiffData {
61
+ generatedFiles: Record<string, string>;
62
+ deletedFiles: string[];
63
+ }
64
+ export type Verdict = "passed" | "failed" | "errored" | "skipped";
65
+ export interface JudgeConfig {
66
+ model: string;
67
+ /** OpenAI 兼容 base url + key 来源;省略则从 env 探测(见 scoring/judge.ts)。 */
68
+ baseUrl?: string;
69
+ apiKeyEnv?: string;
70
+ }
@@ -0,0 +1,29 @@
1
+ import type { Usage } from "../o11y/types.ts";
2
+ import type { EvalResult, ExperimentRunInfo } from "../runner/types.ts";
3
+ import type { Verdict } from "../scoring/types.ts";
4
+ /** 明细行排序:失败最靠前(failed > errored > skipped > passed 的紧急程度)。 */
5
+ export declare const VERDICT_ORDER: Record<Verdict, number>;
6
+ export declare function totalTokens(items: Array<Usage | undefined>): number;
7
+ /** 求和,但「全都没报」时返回 undefined(区别于真 0 成本)。 */
8
+ export declare function sumMaybe(items: Array<number | undefined>): number | undefined;
9
+ export declare function avg(items: number[]): number;
10
+ /** 实验 id 的展示名:取路径最后一段(exp 分组用目录表达)。 */
11
+ export declare function displayExperimentName(id: string | undefined): string | undefined;
12
+ /**
13
+ * 实验 id 的组推导:去掉末段的目录前缀("compare/bub-low" → "compare");
14
+ * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 榜单分组与自定义报告
15
+ * 的分组用同一份,两边的「组」永远指同一个东西。
16
+ */
17
+ export declare function experimentGroupOf(experimentId: string): string | undefined;
18
+ /**
19
+ * eval id 前缀过滤,同 CLI 位置参数的分段语义(src/runner/discover.ts):
20
+ * "algebra" 匹配自身与 "algebra/..." 子级,不误配 "algebra2";允许 "algebra/" 尾斜杠写法,等价。
21
+ */
22
+ export declare function evalPrefixPredicate(evals?: string | string[]): (id: string) => boolean;
23
+ /** 无 experimentId 时的兜底标签。 */
24
+ export declare function fallbackExperimentLabel(result: {
25
+ experiment?: ExperimentRunInfo;
26
+ agent: string;
27
+ model?: string;
28
+ }): string;
29
+ export type { EvalResult };
@@ -0,0 +1,55 @@
1
+ // CLI 表格(runner/reporters/table.ts)与 view 榜单(view/aggregate.ts)共用的聚合小工具。
2
+ // 实验标签推导、token/成本求和、verdict 排序各只有一份 —— 否则同一个实验在终端和网页上
3
+ // 会显示成两个名字 / 两组数。保持环境无关(纯函数,只 type import)。
4
+ /** 明细行排序:失败最靠前(failed > errored > skipped > passed 的紧急程度)。 */
5
+ export const VERDICT_ORDER = {
6
+ failed: 0,
7
+ errored: 1,
8
+ skipped: 2,
9
+ passed: 3,
10
+ };
11
+ export function totalTokens(items) {
12
+ return items.reduce((n, u) => n + (u?.inputTokens ?? 0) + (u?.outputTokens ?? 0), 0);
13
+ }
14
+ /** 求和,但「全都没报」时返回 undefined(区别于真 0 成本)。 */
15
+ export function sumMaybe(items) {
16
+ const known = items.filter((n) => n !== undefined);
17
+ return known.length ? known.reduce((sum, n) => sum + n, 0) : undefined;
18
+ }
19
+ export function avg(items) {
20
+ return items.length ? items.reduce((sum, n) => sum + n, 0) / items.length : 0;
21
+ }
22
+ /** 实验 id 的展示名:取路径最后一段(exp 分组用目录表达)。 */
23
+ export function displayExperimentName(id) {
24
+ if (!id)
25
+ return undefined;
26
+ return id.split("/").filter(Boolean).at(-1) ?? id;
27
+ }
28
+ /**
29
+ * 实验 id 的组推导:去掉末段的目录前缀("compare/bub-low" → "compare");
30
+ * 无 "/" 的顶层实验不属于任何组,返回 undefined。view 榜单分组与自定义报告
31
+ * 的分组用同一份,两边的「组」永远指同一个东西。
32
+ */
33
+ export function experimentGroupOf(experimentId) {
34
+ if (!experimentId.includes("/"))
35
+ return undefined;
36
+ return experimentId.split("/").slice(0, -1).join("/");
37
+ }
38
+ /**
39
+ * eval id 前缀过滤,同 CLI 位置参数的分段语义(src/runner/discover.ts):
40
+ * "algebra" 匹配自身与 "algebra/..." 子级,不误配 "algebra2";允许 "algebra/" 尾斜杠写法,等价。
41
+ */
42
+ export function evalPrefixPredicate(evals) {
43
+ if (evals === undefined)
44
+ return () => true;
45
+ const prefixes = (Array.isArray(evals) ? evals : [evals]).map((p) => p.replace(/\/+$/, ""));
46
+ return (id) => prefixes.some((prefix) => id === prefix || id.startsWith(prefix + "/"));
47
+ }
48
+ /** 无 experimentId 时的兜底标签。 */
49
+ export function fallbackExperimentLabel(result) {
50
+ if (result.experiment?.id)
51
+ return displayExperimentName(result.experiment.id) ?? result.experiment.id;
52
+ if (result.model)
53
+ return `${result.agent}/${result.model}`;
54
+ return result.agent || "ad hoc run";
55
+ }