@tangle-network/agent-bench 0.1.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 (111) hide show
  1. package/README.md +15 -0
  2. package/package.json +35 -0
  3. package/src/adapters.ts +60 -0
  4. package/src/aec-gate.mts +217 -0
  5. package/src/atom-humaneval.mts +197 -0
  6. package/src/atom-mcp-e2e.mts +223 -0
  7. package/src/benchmarks/_harness.ts +206 -0
  8. package/src/benchmarks/aec-bench.test.mts +53 -0
  9. package/src/benchmarks/aec-bench.ts +319 -0
  10. package/src/benchmarks/appworld.test.mts +45 -0
  11. package/src/benchmarks/appworld.ts +426 -0
  12. package/src/benchmarks/cad-design.ts +429 -0
  13. package/src/benchmarks/cadbench.ts +135 -0
  14. package/src/benchmarks/cadgenbench.ts +121 -0
  15. package/src/benchmarks/commit0.test.mts +71 -0
  16. package/src/benchmarks/commit0.ts +266 -0
  17. package/src/benchmarks/enterpriseops-gym.test.mts +77 -0
  18. package/src/benchmarks/enterpriseops-gym.ts +343 -0
  19. package/src/benchmarks/finsearchcomp.ts +371 -0
  20. package/src/benchmarks/frames.ts +520 -0
  21. package/src/benchmarks/hotpotqa.ts +320 -0
  22. package/src/benchmarks/humaneval.ts +251 -0
  23. package/src/benchmarks/mind2web.ts +311 -0
  24. package/src/benchmarks/programbench.test.mts +60 -0
  25. package/src/benchmarks/programbench.ts +210 -0
  26. package/src/benchmarks/simpleqa.ts +390 -0
  27. package/src/benchmarks/swe-bench.ts +152 -0
  28. package/src/benchmarks/terminal-bench.ts +182 -0
  29. package/src/benchmarks/trata-hedge.ts +496 -0
  30. package/src/benchmarks/types.ts +58 -0
  31. package/src/browser/adapters/bad-design-audit.ts +153 -0
  32. package/src/browser/adapters/bad-design-audit.verify.ts +85 -0
  33. package/src/browser/adapters/bad.ts +165 -0
  34. package/src/browser/agent-adapter.ts +145 -0
  35. package/src/browser/process-adapter.ts +146 -0
  36. package/src/browser/run-to-spans.ts +105 -0
  37. package/src/browser/run-to-spans.verify.ts +89 -0
  38. package/src/browser/ui-reviewer.ts +200 -0
  39. package/src/browser/ui-reviewer.verify.ts +94 -0
  40. package/src/browser/verify.ts +96 -0
  41. package/src/clbench-codebase-gate.mts +314 -0
  42. package/src/clbench-context-gate.mts +305 -0
  43. package/src/cloud-loop.mts +138 -0
  44. package/src/coding-skills/minimal-diff.md +9 -0
  45. package/src/coding-skills/read-before-edit.md +9 -0
  46. package/src/coding-skills/reproduce-first.md +10 -0
  47. package/src/coding-skills/run-tests-after-edit.md +9 -0
  48. package/src/coding-skills/trace-the-failure.md +9 -0
  49. package/src/commit0-env-run.mts +59 -0
  50. package/src/commit0-env.ts +173 -0
  51. package/src/commit0-gate.mts +529 -0
  52. package/src/commit0-prereqs.sh +48 -0
  53. package/src/corpus-replay.mts +300 -0
  54. package/src/corpus-report.mts +504 -0
  55. package/src/corpus.test.mts +273 -0
  56. package/src/corpus.ts +325 -0
  57. package/src/decoder-live.mts +133 -0
  58. package/src/directives.ts +84 -0
  59. package/src/diverse-gate.mjs +112 -0
  60. package/src/egress-probe.mts +26 -0
  61. package/src/eops-skills/address-every-subtask.md +5 -0
  62. package/src/eops-skills/exact-tools-and-args.md +5 -0
  63. package/src/eops-skills/full-sequence-to-goal.md +5 -0
  64. package/src/eops-skills/ground-every-value.md +5 -0
  65. package/src/eops-skills/honor-the-policies.md +5 -0
  66. package/src/examples/README.md +58 -0
  67. package/src/examples/math-demo.mts +110 -0
  68. package/src/examples/strategy-demo.mts +119 -0
  69. package/src/fleet.mts +121 -0
  70. package/src/gate-cli.mts +101 -0
  71. package/src/gate.test.mts +129 -0
  72. package/src/gate.ts +460 -0
  73. package/src/generate-eval/certify.ts +178 -0
  74. package/src/generate-eval/schema.ts +78 -0
  75. package/src/humaneval-gate.mts +204 -0
  76. package/src/humaneval-repair-gate.mts +143 -0
  77. package/src/index.ts +19 -0
  78. package/src/mcp-mount-probe.mts +126 -0
  79. package/src/profile-coordinates.ts +134 -0
  80. package/src/profiles.ts +128 -0
  81. package/src/refine-loop.test.mts +106 -0
  82. package/src/refine-loop.ts +106 -0
  83. package/src/research-gate.mts +132 -0
  84. package/src/research-shot.ts +134 -0
  85. package/src/resolve-client.ts +58 -0
  86. package/src/router-executor.ts +51 -0
  87. package/src/run-pool.ts +48 -0
  88. package/src/runtime-hook-recorder.ts +137 -0
  89. package/src/sandbox-run.ts +125 -0
  90. package/src/search-bench/bridge.ts +124 -0
  91. package/src/search-bench/export.mts +0 -0
  92. package/src/search-bench/parametric-check.mts +63 -0
  93. package/src/search-bench/profiles.ts +98 -0
  94. package/src/search-bench/run.mts +287 -0
  95. package/src/search-bench/tasks-fresh.ts +688 -0
  96. package/src/search-bench/tasks.ts +129 -0
  97. package/src/search-tool.ts +95 -0
  98. package/src/selector.test.mts +189 -0
  99. package/src/selector.ts +366 -0
  100. package/src/skill-sandbox-smoke.mts +100 -0
  101. package/src/stats.mts +90 -0
  102. package/src/terminal-compare.ts +519 -0
  103. package/src/trajectory-assemble.mjs +130 -0
  104. package/src/trata-gate.mts +243 -0
  105. package/src/trata-gepa.mts +434 -0
  106. package/src/worker-blender.ts +230 -0
  107. package/src/worker-browser.ts +102 -0
  108. package/src/worker-build123d.ts +143 -0
  109. package/src/worker-cad.ts +451 -0
  110. package/src/worker.ts +136 -0
  111. package/src/workspace-loop.mts +133 -0
@@ -0,0 +1,173 @@
1
+ /**
2
+ * Commit0 as an `Environment` — the HARD test (docs/research/long-horizon-benchmark-survey.md:
3
+ * the survey's top pick, graded + natively multi-stage). The agent implements an entire
4
+ * stubbed Python library so its existing test suite passes.
5
+ *
6
+ * Off-box construction (routes around the sandbox platform exactly like the EOPS gym):
7
+ * open() — clone the stub repo at base_commit into a tmpdir, start a PERSISTENT
8
+ * python:<ver>-slim container with the workspace mounted, `pip install -e .`
9
+ * + pytest once. The container is the artifact; it carries across shots.
10
+ * tools() — list_files / read_file / write_file / run_tests. The worker EDITS SOURCE
11
+ * VIA TOOLS (no diff emission). write_file is path-jailed and refuses the
12
+ * test dir — the agent cannot edit the check.
13
+ * score() — the repo's OWN pytest suite (passed/total), parsed from a quiet run inside
14
+ * the container. Deterministic, deployable. (The official commit0 harness can
15
+ * re-validate a winner from `git diff` later; it is not in the loop.)
16
+ * close() — kill the container, remove the tmpdir.
17
+ */
18
+ import { execFile } from 'node:child_process'
19
+ import { mkdtempSync, rmSync } from 'node:fs'
20
+ import { tmpdir } from 'node:os'
21
+ import { join } from 'node:path'
22
+ import { promisify } from 'node:util'
23
+ import type { AgenticSurface, AgenticTask, AgenticTool, ArtifactHandle, SurfaceScore } from '@tangle-network/agent-runtime/loops'
24
+
25
+ const exec = promisify(execFile)
26
+
27
+ export interface Commit0Row {
28
+ instance_id: string
29
+ repo: string
30
+ base_commit: string
31
+ setup: { install: string; pre_install?: string[] | null; python: string; specification?: string }
32
+ src_dir: string
33
+ test: { test_cmd: string; test_dir: string }
34
+ }
35
+
36
+ interface Ws {
37
+ dir: string
38
+ container: string
39
+ row: Commit0Row
40
+ }
41
+ const workspaces = new Map<string, Ws>()
42
+
43
+ async function dockerExec(container: string, cmd: string, timeoutMs = 180_000): Promise<{ out: string; code: number }> {
44
+ try {
45
+ const r = await exec('docker', ['exec', container, 'bash', '-lc', cmd], { timeout: timeoutMs, maxBuffer: 8 * 1024 * 1024 })
46
+ return { out: `${r.stdout}\n${r.stderr}`.trim(), code: 0 }
47
+ } catch (e) {
48
+ const err = e as { stdout?: string; stderr?: string; code?: number }
49
+ return { out: `${err.stdout ?? ''}\n${err.stderr ?? ''}`.trim(), code: typeof err.code === 'number' ? err.code : 1 }
50
+ }
51
+ }
52
+
53
+ /** Parse pytest's summary tail ("X passed", "Y failed", "Z errors") into counts. */
54
+ function parsePytest(out: string): { passed: number; failed: number } {
55
+ const grab = (re: RegExp) => {
56
+ const m = out.match(re)
57
+ return m ? Number(m[1]) : 0
58
+ }
59
+ return {
60
+ passed: grab(/(\d+) passed/),
61
+ failed: grab(/(\d+) failed/) + grab(/(\d+) error/),
62
+ }
63
+ }
64
+
65
+ export function rowToTask(row: Commit0Row): AgenticTask {
66
+ return {
67
+ id: row.instance_id,
68
+ systemPrompt:
69
+ 'You are a senior Python engineer implementing a stubbed library so its existing test suite passes. ' +
70
+ 'Workflow: list_files and read the tests + stubs to learn the required behavior, write COMPLETE implementations ' +
71
+ `with write_file (source under ${row.src_dir} only — the test dir is read-only), then run_tests and fix failures. ` +
72
+ 'Iterate until the suite passes. Reply DONE only when run_tests shows no failures.',
73
+ userPrompt:
74
+ `Implement the stubbed library "${row.repo}". The public functions/classes under \`${row.src_dir}\` have empty bodies. ` +
75
+ `Make the existing tests under \`${row.test.test_dir}\` pass.${row.setup.specification ? ` Spec: ${row.setup.specification}` : ''}`,
76
+ meta: { instanceId: row.instance_id },
77
+ }
78
+ }
79
+
80
+ export function createCommit0Environment(rows: Commit0Row[]): AgenticSurface {
81
+ const byId = new Map(rows.map((r) => [r.instance_id, r]))
82
+ return {
83
+ name: 'commit0',
84
+ async open(task) {
85
+ const row = byId.get(task.id)
86
+ if (!row) throw new Error(`commit0-env: unknown task ${task.id}`)
87
+ const dir = mkdtempSync(join(tmpdir(), 'c0-'))
88
+ await exec('git', ['clone', '--quiet', `https://github.com/${row.repo}.git`, dir], { timeout: 120_000 })
89
+ await exec('git', ['-C', dir, 'checkout', '--quiet', row.base_commit], { timeout: 60_000 })
90
+ const container = `c0-${task.id.replace(/[^a-z0-9]/gi, '-')}-${Math.random().toString(36).slice(2, 8)}`
91
+ await exec('docker', ['run', '-d', '--name', container, '--cpus=2', '--memory=2g', '-v', `${dir}:/w`, '-w', '/w', `python:${row.setup.python}-slim`, 'sleep', 'infinity'], { timeout: 120_000 })
92
+ for (const pre of row.setup.pre_install ?? []) await dockerExec(container, pre, 300_000)
93
+ const setup = await dockerExec(container, `${row.setup.install} && pip install -q pytest`, 600_000)
94
+ if (setup.code !== 0) {
95
+ await dockerExec(container, 'find /w -mindepth 1 -delete', 60_000).catch(() => {})
96
+ await exec('docker', ['rm', '-f', container]).catch(() => {})
97
+ rmSync(dir, { recursive: true, force: true })
98
+ throw new Error(`commit0-env setup failed for ${task.id}: ${setup.out.slice(-300)}`)
99
+ }
100
+ const handle: ArtifactHandle = { id: container, surface: 'commit0' }
101
+ workspaces.set(container, { dir, container, row })
102
+ return handle
103
+ },
104
+
105
+ async tools(task) {
106
+ const row = byId.get(task.id)
107
+ const src = row?.src_dir ?? 'src/'
108
+ const tests = row?.test.test_dir ?? 'tests/'
109
+ return [
110
+ { type: 'function', function: { name: 'list_files', description: `List the repo's source (${src}) and test (${tests}) files.`, parameters: { type: 'object', properties: {} } } },
111
+ { type: 'function', function: { name: 'read_file', description: 'Read a file from the repo (bounded).', parameters: { type: 'object', properties: { path: { type: 'string' } }, required: ['path'] } } },
112
+ { type: 'function', function: { name: 'write_file', description: `Write COMPLETE file contents (source under ${src} only; the test dir is read-only).`, parameters: { type: 'object', properties: { path: { type: 'string' }, content: { type: 'string' } }, required: ['path', 'content'] } } },
113
+ { type: 'function', function: { name: 'run_tests', description: 'Run the existing test suite; returns the pytest summary + failure tails.', parameters: { type: 'object', properties: {} } } },
114
+ ] satisfies AgenticTool[]
115
+ },
116
+
117
+ async call(handle, name, args) {
118
+ const ws = workspaces.get(handle.id)
119
+ if (!ws) return 'ERROR: workspace closed'
120
+ const jail = (p: string): string | null => {
121
+ const norm = p.replace(/^\.?\//, '')
122
+ if (norm.includes('..') || norm.startsWith('/')) return null
123
+ return norm
124
+ }
125
+ if (name === 'list_files') {
126
+ const r = await dockerExec(ws.container, `find ${ws.row.src_dir} ${ws.row.test.test_dir} -name '*.py' | head -80`, 30_000)
127
+ return r.out.slice(0, 2000)
128
+ }
129
+ if (name === 'read_file') {
130
+ const p = jail(String(args.path ?? ''))
131
+ if (!p) return 'ERROR: invalid path'
132
+ const r = await dockerExec(ws.container, `cat ${JSON.stringify(p)}`, 30_000)
133
+ return r.code === 0 ? r.out.slice(0, 8000) : `ERROR: ${r.out.slice(0, 200)}`
134
+ }
135
+ if (name === 'write_file') {
136
+ const p = jail(String(args.path ?? ''))
137
+ if (!p) return 'ERROR: invalid path'
138
+ if (p.startsWith(ws.row.test.test_dir.replace(/^\.?\//, ''))) return 'ERROR: the test dir is read-only — implement the source, not the tests'
139
+ const content = String(args.content ?? '')
140
+ const b64 = Buffer.from(content, 'utf8').toString('base64')
141
+ const r = await dockerExec(ws.container, `mkdir -p $(dirname ${JSON.stringify(p)}) && echo '${b64}' | base64 -d > ${JSON.stringify(p)}`, 30_000)
142
+ return r.code === 0 ? `wrote ${p} (${content.length} chars)` : `ERROR: ${r.out.slice(0, 200)}`
143
+ }
144
+ if (name === 'run_tests') {
145
+ // `-o addopts=` neutralizes repo-configured pytest plugins (e.g. wcwidth's tox.ini
146
+ // demands pytest-cov) that aren't installed and would usage-error before any test runs.
147
+ const r = await dockerExec(ws.container, `${ws.row.test.test_cmd} ${ws.row.test.test_dir} -q --tb=line -p no:cacheprovider -o addopts= 2>&1 | tail -30`, 240_000)
148
+ return r.out.slice(0, 2500)
149
+ }
150
+ return `ERROR: unknown tool ${name}`
151
+ },
152
+
153
+ async score(_task, handle) {
154
+ const ws = workspaces.get(handle.id)
155
+ if (!ws) return { passes: 0, total: 0, errored: 1 }
156
+ const r = await dockerExec(ws.container, `${ws.row.test.test_cmd} ${ws.row.test.test_dir} -q --tb=no -p no:cacheprovider -o addopts= 2>&1 | tail -5`, 240_000)
157
+ const { passed, failed } = parsePytest(r.out)
158
+ const total = passed + failed
159
+ return total > 0 ? { passes: passed, total, errored: 0 } : { passes: 0, total: 0, errored: 1 }
160
+ },
161
+
162
+ async close(handle) {
163
+ const ws = workspaces.get(handle.id)
164
+ if (!ws) return
165
+ workspaces.delete(handle.id)
166
+ // The container ran as root, so its writes on the bind mount are root-owned and the
167
+ // host rmSync would EACCES — wipe the mount from INSIDE the container first.
168
+ await dockerExec(ws.container, 'find /w -mindepth 1 -delete', 60_000).catch(() => {})
169
+ await exec('docker', ['rm', '-f', ws.container]).catch(() => {})
170
+ rmSync(ws.dir, { recursive: true, force: true })
171
+ },
172
+ }
173
+ }