@tangle-network/agent-bench 0.4.1 → 0.4.3

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 (194) hide show
  1. package/CHANGELOG.md +9 -0
  2. package/dist/adapters.d.ts +4 -11
  3. package/dist/adapters.js +78 -41
  4. package/dist/adapters.js.map +1 -1
  5. package/dist/benchmarks/_harness.d.ts +48 -66
  6. package/dist/benchmarks/_harness.js +329 -33
  7. package/dist/benchmarks/_harness.js.map +1 -1
  8. package/dist/benchmarks/aec-bench.d.ts +4 -25
  9. package/dist/benchmarks/aec-bench.js +242 -7
  10. package/dist/benchmarks/aec-bench.js.map +1 -1
  11. package/dist/benchmarks/agentbench.d.ts +5 -13
  12. package/dist/benchmarks/agentbench.js +114 -9
  13. package/dist/benchmarks/agentbench.js.map +1 -1
  14. package/dist/benchmarks/appworld.d.ts +9 -29
  15. package/dist/benchmarks/appworld.js +317 -12
  16. package/dist/benchmarks/appworld.js.map +1 -1
  17. package/dist/benchmarks/bfcl.d.ts +5 -15
  18. package/dist/benchmarks/bfcl.js +264 -9
  19. package/dist/benchmarks/bfcl.js.map +1 -1
  20. package/dist/benchmarks/cad-design.d.ts +16 -41
  21. package/dist/benchmarks/cad-design.js +512 -6
  22. package/dist/benchmarks/cad-design.js.map +1 -1
  23. package/dist/benchmarks/cadbench.d.ts +4 -17
  24. package/dist/benchmarks/cadbench.js +2 -8
  25. package/dist/benchmarks/cadgenbench.d.ts +4 -20
  26. package/dist/benchmarks/cadgenbench.js +2 -8
  27. package/dist/benchmarks/commit0.d.ts +5 -27
  28. package/dist/benchmarks/commit0.js +187 -9
  29. package/dist/benchmarks/commit0.js.map +1 -1
  30. package/dist/benchmarks/crag.d.ts +4 -12
  31. package/dist/benchmarks/crag.js +110 -8
  32. package/dist/benchmarks/crag.js.map +1 -1
  33. package/dist/benchmarks/dabstep.d.ts +5 -15
  34. package/dist/benchmarks/dabstep.js +177 -9
  35. package/dist/benchmarks/dabstep.js.map +1 -1
  36. package/dist/benchmarks/enterpriseops-gym.d.ts +5 -34
  37. package/dist/benchmarks/enterpriseops-gym.js +236 -9
  38. package/dist/benchmarks/enterpriseops-gym.js.map +1 -1
  39. package/dist/benchmarks/finresearchbench.d.ts +4 -13
  40. package/dist/benchmarks/finresearchbench.js +218 -7
  41. package/dist/benchmarks/finresearchbench.js.map +1 -1
  42. package/dist/benchmarks/finsearchcomp.d.ts +8 -39
  43. package/dist/benchmarks/finsearchcomp.js +267 -6
  44. package/dist/benchmarks/finsearchcomp.js.map +1 -1
  45. package/dist/benchmarks/frames.d.ts +15 -37
  46. package/dist/benchmarks/frames.js +408 -11
  47. package/dist/benchmarks/frames.js.map +1 -1
  48. package/dist/benchmarks/hotpotqa.d.ts +4 -24
  49. package/dist/benchmarks/hotpotqa.js +250 -14
  50. package/dist/benchmarks/hotpotqa.js.map +1 -1
  51. package/dist/benchmarks/humaneval.d.ts +19 -37
  52. package/dist/benchmarks/humaneval.js +279 -16
  53. package/dist/benchmarks/humaneval.js.map +1 -1
  54. package/dist/benchmarks/mind2web.d.ts +7 -34
  55. package/dist/benchmarks/mind2web.js +257 -8
  56. package/dist/benchmarks/mind2web.js.map +1 -1
  57. package/dist/benchmarks/nomiracl.d.ts +4 -13
  58. package/dist/benchmarks/nomiracl.js +146 -8
  59. package/dist/benchmarks/nomiracl.js.map +1 -1
  60. package/dist/benchmarks/open-rag-bench.d.ts +4 -12
  61. package/dist/benchmarks/open-rag-bench.js +110 -8
  62. package/dist/benchmarks/open-rag-bench.js.map +1 -1
  63. package/dist/benchmarks/programbench.d.ts +5 -29
  64. package/dist/benchmarks/programbench.js +161 -9
  65. package/dist/benchmarks/programbench.js.map +1 -1
  66. package/dist/benchmarks/rag-shared.d.ts +21 -20
  67. package/dist/benchmarks/rag-shared.js +245 -38
  68. package/dist/benchmarks/rag-shared.js.map +1 -1
  69. package/dist/benchmarks/ragbench.d.ts +4 -14
  70. package/dist/benchmarks/ragbench.js +127 -8
  71. package/dist/benchmarks/ragbench.js.map +1 -1
  72. package/dist/benchmarks/simpleqa.d.ts +17 -44
  73. package/dist/benchmarks/simpleqa.js +293 -10
  74. package/dist/benchmarks/simpleqa.js.map +1 -1
  75. package/dist/benchmarks/swe-bench.d.ts +23 -36
  76. package/dist/benchmarks/swe-bench.js +234 -13
  77. package/dist/benchmarks/swe-bench.js.map +1 -1
  78. package/dist/benchmarks/t2-ragbench.d.ts +4 -12
  79. package/dist/benchmarks/t2-ragbench.js +118 -8
  80. package/dist/benchmarks/t2-ragbench.js.map +1 -1
  81. package/dist/benchmarks/tau-bench-shared.d.ts +14 -22
  82. package/dist/benchmarks/tau-bench-shared.js +169 -9
  83. package/dist/benchmarks/tau-bench-shared.js.map +1 -1
  84. package/dist/benchmarks/tau2-bench.d.ts +5 -5
  85. package/dist/benchmarks/tau2-bench.js +28 -10
  86. package/dist/benchmarks/tau2-bench.js.map +1 -1
  87. package/dist/benchmarks/tau3-banking.d.ts +4 -13
  88. package/dist/benchmarks/tau3-banking.js +28 -8
  89. package/dist/benchmarks/tau3-banking.js.map +1 -1
  90. package/dist/benchmarks/terminal-bench.d.ts +4 -22
  91. package/dist/benchmarks/terminal-bench.js +140 -7
  92. package/dist/benchmarks/terminal-bench.js.map +1 -1
  93. package/dist/benchmarks/toollm.d.ts +5 -13
  94. package/dist/benchmarks/toollm.js +184 -9
  95. package/dist/benchmarks/toollm.js.map +1 -1
  96. package/dist/benchmarks/trata-hedge.d.ts +4 -30
  97. package/dist/benchmarks/trata-hedge.js +336 -6
  98. package/dist/benchmarks/trata-hedge.js.map +1 -1
  99. package/dist/benchmarks/types.d.ts +85 -94
  100. package/dist/benchmarks/types.js +1 -1
  101. package/dist/benchmarks/webarena-verified.d.ts +5 -13
  102. package/dist/benchmarks/webarena-verified.js +152 -9
  103. package/dist/benchmarks/webarena-verified.js.map +1 -1
  104. package/dist/cadbench-DpQWZHp4.js +285 -0
  105. package/dist/cadbench-DpQWZHp4.js.map +1 -0
  106. package/dist/cadgenbench-DRhczfsG.js +151 -0
  107. package/dist/cadgenbench-DRhczfsG.js.map +1 -0
  108. package/dist/index.d.ts +245 -293
  109. package/dist/index.js +1669 -1791
  110. package/dist/index.js.map +1 -1
  111. package/package.json +17 -14
  112. package/scripts/verify-packed-consumer.mjs +20 -17
  113. package/src/corpus.test.mts +13 -0
  114. package/src/corpus.ts +4 -0
  115. package/src/profile-coordinates.ts +2 -2
  116. package/src/rollout-ledger/backfill-swe-arena.mts +5 -1
  117. package/src/rollout-ledger/settle-capture.mts +7 -1
  118. package/src/search-bench/profiles.ts +1 -1
  119. package/src/skill-sandbox-smoke.mts +2 -1
  120. package/src/swe-arena/gepa-seat.mts +1 -1
  121. package/src/swe-arena/ledger-orphans.test.mts +36 -34
  122. package/dist/benchmarks/cadbench.js.map +0 -1
  123. package/dist/benchmarks/cadgenbench.js.map +0 -1
  124. package/dist/benchmarks/types.js.map +0 -1
  125. package/dist/chunk-53UPUNBZ.js +0 -325
  126. package/dist/chunk-53UPUNBZ.js.map +0 -1
  127. package/dist/chunk-5FEQDSCT.js +0 -211
  128. package/dist/chunk-5FEQDSCT.js.map +0 -1
  129. package/dist/chunk-5H5XV76F.js +0 -240
  130. package/dist/chunk-5H5XV76F.js.map +0 -1
  131. package/dist/chunk-67ACKDCX.js +0 -118
  132. package/dist/chunk-67ACKDCX.js.map +0 -1
  133. package/dist/chunk-7FKBWOQT.js +0 -147
  134. package/dist/chunk-7FKBWOQT.js.map +0 -1
  135. package/dist/chunk-BEN6IF2X.js +0 -221
  136. package/dist/chunk-BEN6IF2X.js.map +0 -1
  137. package/dist/chunk-BZY5QARD.js +0 -120
  138. package/dist/chunk-BZY5QARD.js.map +0 -1
  139. package/dist/chunk-C7T7WEK2.js +0 -103
  140. package/dist/chunk-C7T7WEK2.js.map +0 -1
  141. package/dist/chunk-CLIKAXKH.js +0 -276
  142. package/dist/chunk-CLIKAXKH.js.map +0 -1
  143. package/dist/chunk-CWIOBFSP.js +0 -197
  144. package/dist/chunk-CWIOBFSP.js.map +0 -1
  145. package/dist/chunk-CXDUTWQE.js +0 -318
  146. package/dist/chunk-CXDUTWQE.js.map +0 -1
  147. package/dist/chunk-DWALFME7.js +0 -182
  148. package/dist/chunk-DWALFME7.js.map +0 -1
  149. package/dist/chunk-EEOC6QPJ.js +0 -144
  150. package/dist/chunk-EEOC6QPJ.js.map +0 -1
  151. package/dist/chunk-EIETHPD5.js +0 -321
  152. package/dist/chunk-EIETHPD5.js.map +0 -1
  153. package/dist/chunk-GC2EPS6L.js +0 -130
  154. package/dist/chunk-GC2EPS6L.js.map +0 -1
  155. package/dist/chunk-GCHL6XPM.js +0 -169
  156. package/dist/chunk-GCHL6XPM.js.map +0 -1
  157. package/dist/chunk-HQ5HCCKF.js +0 -142
  158. package/dist/chunk-HQ5HCCKF.js.map +0 -1
  159. package/dist/chunk-HVW25KSX.js +0 -208
  160. package/dist/chunk-HVW25KSX.js.map +0 -1
  161. package/dist/chunk-INNOYXCP.js +0 -387
  162. package/dist/chunk-INNOYXCP.js.map +0 -1
  163. package/dist/chunk-J6BU3NTM.js +0 -251
  164. package/dist/chunk-J6BU3NTM.js.map +0 -1
  165. package/dist/chunk-JSQOUKXS.js +0 -149
  166. package/dist/chunk-JSQOUKXS.js.map +0 -1
  167. package/dist/chunk-JTHWEDEW.js +0 -32
  168. package/dist/chunk-JTHWEDEW.js.map +0 -1
  169. package/dist/chunk-NRMGT25X.js +0 -116
  170. package/dist/chunk-NRMGT25X.js.map +0 -1
  171. package/dist/chunk-PA2ZKHJC.js +0 -230
  172. package/dist/chunk-PA2ZKHJC.js.map +0 -1
  173. package/dist/chunk-PUIRNYI7.js +0 -189
  174. package/dist/chunk-PUIRNYI7.js.map +0 -1
  175. package/dist/chunk-QZZEAHWJ.js +0 -136
  176. package/dist/chunk-QZZEAHWJ.js.map +0 -1
  177. package/dist/chunk-SEVJPLZC.js +0 -260
  178. package/dist/chunk-SEVJPLZC.js.map +0 -1
  179. package/dist/chunk-TBKU5XQI.js +0 -228
  180. package/dist/chunk-TBKU5XQI.js.map +0 -1
  181. package/dist/chunk-UPAMRDX4.js +0 -233
  182. package/dist/chunk-UPAMRDX4.js.map +0 -1
  183. package/dist/chunk-VQRS7VUC.js +0 -342
  184. package/dist/chunk-VQRS7VUC.js.map +0 -1
  185. package/dist/chunk-WG7TM7UV.js +0 -30
  186. package/dist/chunk-WG7TM7UV.js.map +0 -1
  187. package/dist/chunk-X3BTXCJ4.js +0 -262
  188. package/dist/chunk-X3BTXCJ4.js.map +0 -1
  189. package/dist/chunk-XXFF3RRD.js +0 -162
  190. package/dist/chunk-XXFF3RRD.js.map +0 -1
  191. package/dist/chunk-ZFNOM7WR.js +0 -27
  192. package/dist/chunk-ZFNOM7WR.js.map +0 -1
  193. package/dist/chunk-ZNCCYTFG.js +0 -170
  194. package/dist/chunk-ZNCCYTFG.js.map +0 -1
@@ -1,221 +0,0 @@
1
- import {
2
- benchRoot,
3
- preflightVenvImports,
4
- readJsonReport,
5
- runStagedJudge,
6
- stageFile,
7
- venvPython
8
- } from "./chunk-EIETHPD5.js";
9
-
10
- // src/benchmarks/aec-bench.ts
11
- import { readFile } from "fs/promises";
12
- import { join } from "path";
13
- var FIXTURES = join(benchRoot, "fixtures", "aec-bench.json");
14
- var REPO = "TheodoreGalanos/aec-bench";
15
- var RAW = `https://raw.githubusercontent.com/${REPO}/main`;
16
- var TREE = `https://api.github.com/repos/${REPO}/git/trees/main?recursive=1`;
17
- var verifyPathPattern = /^tasks\/(.+)\/tests\/verify\.py$/;
18
- var DEFAULT_LIMIT = 10;
19
- function recordToTask(rec) {
20
- const meta = {
21
- taskId: rec.id,
22
- discipline: rec.discipline,
23
- taskToml: rec.task_toml,
24
- verifyPy: rec.verify_py,
25
- goldenPassMd: rec.golden_pass_md
26
- };
27
- return {
28
- id: rec.id,
29
- split: rec.discipline,
30
- // instruction.md is fully self-contained and already specifies the exact JSON
31
- // output schema + the "write to /workspace/output.md" contract the verifier
32
- // keys off — we pass it through verbatim so the verify.py extractor matches.
33
- prompt: rec.instruction,
34
- metadata: meta
35
- };
36
- }
37
- function readMeta(task) {
38
- const md = task.metadata;
39
- if (!md || typeof md.verifyPy !== "string" || typeof md.taskId !== "string") {
40
- throw new Error(`aec-bench task ${task.id} missing verifier metadata \u2014 loadTasks did not populate it`);
41
- }
42
- return md;
43
- }
44
- async function fetchText(url) {
45
- const res = await fetch(url);
46
- if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`);
47
- return res.text();
48
- }
49
- async function fetchTextOrNull(url) {
50
- const res = await fetch(url);
51
- if (res.status === 404) return null;
52
- if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`);
53
- return res.text();
54
- }
55
- async function listAllInstances() {
56
- const res = await fetch(TREE);
57
- if (!res.ok) throw new Error(`aec-bench tree ${res.status}: ${TREE}`);
58
- const { tree } = await res.json();
59
- const ids = [];
60
- for (const entry of tree) {
61
- const m = verifyPathPattern.exec(entry.path);
62
- if (m?.[1]) ids.push(m[1]);
63
- }
64
- return ids;
65
- }
66
- async function fetchInstance(id) {
67
- const base = `${RAW}/tasks/${id}`;
68
- const verify = await fetch(`${base}/tests/verify.py`);
69
- if (verify.status === 404) return null;
70
- if (!verify.ok) throw new Error(`aec-bench fetch ${verify.status}: ${id}/tests/verify.py`);
71
- const [instruction, task_toml, golden_pass_md] = await Promise.all([
72
- fetchText(`${base}/instruction.md`),
73
- fetchText(`${base}/task.toml`),
74
- fetchTextOrNull(`${base}/tests/fixtures/golden_pass.md`)
75
- ]);
76
- return {
77
- id,
78
- discipline: id.split("/")[0] ?? "",
79
- instruction,
80
- task_toml,
81
- verify_py: await verify.text(),
82
- golden_pass_md
83
- };
84
- }
85
- function selectFixtures(records, opts) {
86
- let tasks = records.map(recordToTask);
87
- if (opts.split) tasks = tasks.filter((t) => t.split === opts.split);
88
- if (opts.ids) {
89
- const want = new Set(opts.ids);
90
- tasks = tasks.filter((t) => want.has(t.id));
91
- } else if (opts.limit !== void 0) {
92
- tasks = tasks.slice(0, opts.limit);
93
- }
94
- return tasks;
95
- }
96
- async function loadFixtures(opts) {
97
- const records = JSON.parse(await readFile(FIXTURES, "utf8"));
98
- console.warn(
99
- `[aec-bench] AEC_FIXTURES=1 \u2014 loading ${records.length} committed fixtures from ${FIXTURES} (no GitHub fetch)`
100
- );
101
- return selectFixtures(records, opts);
102
- }
103
- async function loadLive(opts) {
104
- if (opts.ids) {
105
- const records2 = [];
106
- for (const id of opts.ids) {
107
- const rec = await fetchInstance(id);
108
- if (!rec) throw new Error(`aec-bench: ${id} has no tests/verify.py (seed-only or wrong id)`);
109
- records2.push(rec);
110
- }
111
- return records2.map(recordToTask);
112
- }
113
- const limit = opts.limit ?? DEFAULT_LIMIT;
114
- let ids = await listAllInstances();
115
- if (opts.split) ids = ids.filter((id) => id.startsWith(`${opts.split}/`));
116
- const records = [];
117
- for (const id of ids) {
118
- if (records.length >= limit) break;
119
- try {
120
- const rec = await fetchInstance(id);
121
- if (rec) records.push(rec);
122
- } catch (err) {
123
- console.warn(`[aec-bench] skipping ${id}: ${err instanceof Error ? err.message : String(err)}`);
124
- }
125
- }
126
- if (records.length === 0) {
127
- throw new Error(
128
- `aec-bench loadTasks found no runnable instances for ${JSON.stringify(opts)} (no tests/verify.py matched the requested split). Set AEC_FIXTURES=1 to run offline.`
129
- );
130
- }
131
- return records.map(recordToTask);
132
- }
133
- async function runVerifier(meta, artifact) {
134
- return runStagedJudge({
135
- tmpPrefix: "aecbench-",
136
- timeoutMs: 12e4,
137
- async stage(dir) {
138
- await Promise.all([
139
- stageFile(join(dir, "output.md"), artifact),
140
- stageFile(join(dir, "verify.py"), meta.verifyPy)
141
- ]);
142
- },
143
- bin: venvPython,
144
- argv: (dir) => [join(dir, "verify.py"), "--input", join(dir, "output.md"), "--output", join(dir, "reward.json")],
145
- async parseReport(dir) {
146
- const report = await readJsonReport(join(dir, "reward.json"));
147
- const reward = report.reward;
148
- if (typeof reward !== "number" || !Number.isFinite(reward)) {
149
- throw new Error(`aec-bench verify.py wrote no numeric reward for ${meta.taskId}: ${JSON.stringify(report)}`);
150
- }
151
- const details = await readFile(join(dir, "details.json"), "utf8").then(
152
- (s) => JSON.parse(s),
153
- () => ({})
154
- );
155
- const score = Math.max(0, Math.min(1, reward));
156
- return {
157
- // resolved = full credit (all fields within tolerance), matching aec-bench's perfect_rate.
158
- resolved: score >= 1,
159
- score,
160
- detail: JSON.stringify({ taskId: meta.taskId, discipline: meta.discipline, reward, fields: details })
161
- };
162
- }
163
- });
164
- }
165
- function createAecBenchAdapter() {
166
- const fixturesMode = process.env.AEC_FIXTURES === "1";
167
- return {
168
- name: "aec-bench",
169
- async preflight() {
170
- await preflightVenvImports({
171
- modules: ["math", "json", "re"],
172
- requireDocker: false,
173
- fix: "Fix: python3 -m venv bench/.venv (verify.py only needs the stdlib \u2014 no pip install)."
174
- });
175
- if (fixturesMode) {
176
- await readFile(FIXTURES, "utf8").catch((err) => {
177
- throw new Error(`AEC_FIXTURES=1 but ${FIXTURES} unreadable: ${err instanceof Error ? err.message : err}`);
178
- });
179
- return;
180
- }
181
- const res = await fetch(`${RAW}/README.md`, { method: "HEAD" }).catch((err) => {
182
- throw new Error(
183
- `aec-bench preflight failed reaching ${RAW}: ${err instanceof Error ? err.message : err}
184
- Fix: ensure network access to raw.githubusercontent.com, or set AEC_FIXTURES=1 to run offline.`
185
- );
186
- });
187
- if (!res.ok) {
188
- throw new Error(
189
- `aec-bench preflight: ${REPO} README HEAD ${res.status}. Set AEC_FIXTURES=1 to run against committed fixtures.`
190
- );
191
- }
192
- },
193
- async loadTasks(opts = {}) {
194
- if (fixturesMode) return loadFixtures(opts);
195
- try {
196
- return await loadLive(opts);
197
- } catch (err) {
198
- if (err instanceof Error && /fetch \d|ENOTFOUND|getaddrinfo|network/i.test(err.message)) {
199
- console.warn(
200
- `[aec-bench] live fetch failed (${err.message.slice(0, 160)}); falling back to committed fixtures at ${FIXTURES}`
201
- );
202
- return loadFixtures(opts);
203
- }
204
- throw err;
205
- }
206
- },
207
- async goldArtifact(task) {
208
- const meta = readMeta(task);
209
- return meta.goldenPassMd ?? void 0;
210
- },
211
- async judge(task, artifact) {
212
- const meta = readMeta(task);
213
- return runVerifier(meta, artifact);
214
- }
215
- };
216
- }
217
-
218
- export {
219
- createAecBenchAdapter
220
- };
221
- //# sourceMappingURL=chunk-BEN6IF2X.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/benchmarks/aec-bench.ts"],"sourcesContent":["/**\n * AEC-Bench adapter (TheodoreGalanos/aec-bench, MIT) — closed-form\n * Architecture/Engineering/Construction calculation tasks. Worker artifact = a\n * markdown solution ending in a fenced ```json block with the required numeric\n * fields. Judge = the task's OWN `tests/verify.py`, run with python3: it\n * recomputes ground truth from the embedded engineering formulas, extracts the\n * last JSON block from the artifact, scores each field by math.isclose within a\n * per-field rel_tol, and writes {\"reward\": mean} + per-field details.json.\n * GRADED / partial-credit, FULLY DETERMINISTIC — no LLM judge.\n *\n * Distinct from the multimodal nomic-ai/aec-bench; this is the deterministic\n * calculation platform. The runnable-instance verify.py only needs python3 (no\n * Docker, no Harbor) for the pure-calc disciplines, so the local gate runs at\n * conc<=2 without a container backend.\n *\n * Requires for a live run: network to raw.githubusercontent.com /\n * api.github.com (the in-repo tasks tree) + a python3 interpreter (the bench\n * venv) to run verify.py. For offline/CI, set AEC_FIXTURES=1 to load the\n * committed fixtures (bench/fixtures/aec-bench.json) — never a silent fallback.\n */\n\nimport { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { benchRoot, preflightVenvImports, readJsonReport, runStagedJudge, stageFile, venvPython } from './_harness'\nimport type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'\n\nconst FIXTURES = join(benchRoot, 'fixtures', 'aec-bench.json')\n\nconst REPO = 'TheodoreGalanos/aec-bench'\nconst RAW = `https://raw.githubusercontent.com/${REPO}/main`\nconst TREE = `https://api.github.com/repos/${REPO}/git/trees/main?recursive=1`\n\n/** Matches every runnable-instance task id at ANY depth under tasks/. */\nconst verifyPathPattern = /^tasks\\/(.+)\\/tests\\/verify\\.py$/\n\n/** Default cap on tasks enumerated before a `limit` is applied. */\nconst DEFAULT_LIMIT = 10\n\ninterface AecRecord {\n /** Canonical task id `<discipline>/<task>`, e.g. 'electrical/catenary-sag'. */\n id: string\n discipline: string\n /** instruction.md — the self-contained prompt (table + required outputs + JSON schema). */\n instruction: string\n /** task.toml — metadata/difficulty/timeouts (carried for trace context). */\n task_toml: string\n /** tests/verify.py — the deterministic verifier (recomputes GT, scores fields). */\n verify_py: string\n /** tests/fixtures/golden_pass.md — the oracle artifact that scores reward 1.0,\n * when the task ships one. Null when the task only ships a non-md ground truth\n * (e.g. tests/ground_truth.json); the judge never needs it, only goldArtifact does. */\n golden_pass_md: string | null\n}\n\ninterface AecMeta {\n taskId: string\n discipline: string\n taskToml: string\n verifyPy: string\n goldenPassMd: string | null\n}\n\nfunction recordToTask(rec: AecRecord): BenchTask {\n const meta: AecMeta = {\n taskId: rec.id,\n discipline: rec.discipline,\n taskToml: rec.task_toml,\n verifyPy: rec.verify_py,\n goldenPassMd: rec.golden_pass_md,\n }\n return {\n id: rec.id,\n split: rec.discipline,\n // instruction.md is fully self-contained and already specifies the exact JSON\n // output schema + the \"write to /workspace/output.md\" contract the verifier\n // keys off — we pass it through verbatim so the verify.py extractor matches.\n prompt: rec.instruction,\n metadata: meta as unknown as Record<string, unknown>,\n }\n}\n\nfunction readMeta(task: BenchTask): AecMeta {\n const md = task.metadata\n // Gold is optional (goldenPassMd may be null) — only the verifier + id are required.\n if (!md || typeof md.verifyPy !== 'string' || typeof md.taskId !== 'string') {\n throw new Error(`aec-bench task ${task.id} missing verifier metadata — loadTasks did not populate it`)\n }\n return md as unknown as AecMeta\n}\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`)\n return res.text()\n}\n\n/** Like fetchText but returns null on a 404 (absent optional file); throws on any other non-OK. */\nasync function fetchTextOrNull(url: string): Promise<string | null> {\n const res = await fetch(url)\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`)\n return res.text()\n}\n\ninterface GitTree {\n tree: Array<{ path: string; type: string }>\n}\n\n/**\n * One recursive git-tree call enumerates EVERY runnable-instance id at any depth:\n * a task is runnable iff it ships tests/verify.py. The captured group is the id\n * `tasks/<id>/tests/verify.py` → `<id>` (e.g. 'electrical/pf-droop', or a deeper\n * '<discipline>/<family>/<task>'). Throws loud on a non-OK tree response.\n */\nasync function listAllInstances(): Promise<string[]> {\n const res = await fetch(TREE)\n if (!res.ok) throw new Error(`aec-bench tree ${res.status}: ${TREE}`)\n const { tree } = (await res.json()) as GitTree\n const ids: string[] = []\n for (const entry of tree) {\n const m = verifyPathPattern.exec(entry.path)\n if (m?.[1]) ids.push(m[1])\n }\n return ids\n}\n\n/**\n * Fetch one task's instruction.md + task.toml + tests/verify.py + golden_pass.md.\n * Returns null when the dir is a SEED (no runnable verify.py) so enumeration can\n * skip it without faking a task. Gold is OPTIONAL — a task that ships a non-md\n * ground truth (e.g. tests/ground_truth.json) yields golden_pass_md=null; the\n * deterministic judge needs only verify.py.\n */\nasync function fetchInstance(id: string): Promise<AecRecord | null> {\n const base = `${RAW}/tasks/${id}`\n const verify = await fetch(`${base}/tests/verify.py`)\n if (verify.status === 404) return null\n if (!verify.ok) throw new Error(`aec-bench fetch ${verify.status}: ${id}/tests/verify.py`)\n const [instruction, task_toml, golden_pass_md] = await Promise.all([\n fetchText(`${base}/instruction.md`),\n fetchText(`${base}/task.toml`),\n fetchTextOrNull(`${base}/tests/fixtures/golden_pass.md`),\n ])\n return {\n id,\n discipline: id.split('/')[0] ?? '',\n instruction,\n task_toml,\n verify_py: await verify.text(),\n golden_pass_md,\n }\n}\n\nfunction selectFixtures(records: AecRecord[], opts: LoadOptions): BenchTask[] {\n let tasks = records.map(recordToTask)\n if (opts.split) tasks = tasks.filter((t) => t.split === opts.split)\n if (opts.ids) {\n const want = new Set(opts.ids)\n tasks = tasks.filter((t) => want.has(t.id))\n } else if (opts.limit !== undefined) {\n tasks = tasks.slice(0, opts.limit)\n }\n return tasks\n}\n\nasync function loadFixtures(opts: LoadOptions): Promise<BenchTask[]> {\n const records = JSON.parse(await readFile(FIXTURES, 'utf8')) as AecRecord[]\n console.warn(\n `[aec-bench] AEC_FIXTURES=1 — loading ${records.length} committed fixtures from ${FIXTURES} (no GitHub fetch)`,\n )\n return selectFixtures(records, opts)\n}\n\n/** Enumerate live tasks: explicit ids (each required — throws on a bad id), or a\n * capped slice of the recursive tree (optionally filtered to one split). Per-task\n * resilient: a single fetch failure warns + SKIPS that task, never aborting the\n * batch. Skips seed dirs (no verify.py) — never fabricates. */\nasync function loadLive(opts: LoadOptions): Promise<BenchTask[]> {\n if (opts.ids) {\n const records: AecRecord[] = []\n for (const id of opts.ids) {\n const rec = await fetchInstance(id)\n if (!rec) throw new Error(`aec-bench: ${id} has no tests/verify.py (seed-only or wrong id)`)\n records.push(rec)\n }\n return records.map(recordToTask)\n }\n const limit = opts.limit ?? DEFAULT_LIMIT\n let ids = await listAllInstances()\n if (opts.split) ids = ids.filter((id) => id.startsWith(`${opts.split}/`))\n const records: AecRecord[] = []\n for (const id of ids) {\n if (records.length >= limit) break\n try {\n const rec = await fetchInstance(id)\n if (rec) records.push(rec)\n } catch (err) {\n // One bad task must NEVER abort the batch — warn and skip it.\n console.warn(`[aec-bench] skipping ${id}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n if (records.length === 0) {\n throw new Error(\n `aec-bench loadTasks found no runnable instances for ${JSON.stringify(opts)} ` +\n `(no tests/verify.py matched the requested split). Set AEC_FIXTURES=1 to run offline.`,\n )\n }\n return records.map(recordToTask)\n}\n\n/**\n * Run the task's own verify.py with python3 over the artifact via the shared\n * staged-judge spine (mkdtemp → stage → spawn → parseReport → cleanup). verify.py\n * writes {\"reward\": mean} to --output and per-field details.json as a sibling. We\n * read both: reward → graded score; details → sub-scores for the trace-analyst.\n * Fail loud if the verifier never wrote a numeric reward (a crashed verifier is\n * NOT a silent 0 — verify.py's own except-trap writes reward 0.0, so an absent /\n * non-numeric reward.json is a real bug, surfaced by readJsonReport).\n */\nasync function runVerifier(meta: AecMeta, artifact: string): Promise<BenchScore> {\n return runStagedJudge({\n tmpPrefix: 'aecbench-',\n timeoutMs: 120_000,\n async stage(dir) {\n await Promise.all([\n stageFile(join(dir, 'output.md'), artifact),\n stageFile(join(dir, 'verify.py'), meta.verifyPy),\n ])\n },\n bin: venvPython,\n argv: (dir) => [join(dir, 'verify.py'), '--input', join(dir, 'output.md'), '--output', join(dir, 'reward.json')],\n async parseReport(dir) {\n const report = await readJsonReport<{ reward?: number }>(join(dir, 'reward.json'))\n const reward = report.reward\n if (typeof reward !== 'number' || !Number.isFinite(reward)) {\n throw new Error(`aec-bench verify.py wrote no numeric reward for ${meta.taskId}: ${JSON.stringify(report)}`)\n }\n const details = await readFile(join(dir, 'details.json'), 'utf8').then(\n (s) => JSON.parse(s) as Record<string, number>,\n () => ({}),\n )\n const score = Math.max(0, Math.min(1, reward))\n return {\n // resolved = full credit (all fields within tolerance), matching aec-bench's perfect_rate.\n resolved: score >= 1,\n score,\n detail: JSON.stringify({ taskId: meta.taskId, discipline: meta.discipline, reward, fields: details }),\n }\n },\n })\n}\n\nexport function createAecBenchAdapter(): BenchmarkAdapter {\n const fixturesMode = process.env.AEC_FIXTURES === '1'\n\n return {\n name: 'aec-bench',\n\n async preflight() {\n // The verifier is python3 over the stdlib (math/json/re) — no pip install.\n // Reuse the shared import-probe so the bench venv interpreter is proven to\n // exist + run before any judge spawns verify.py.\n await preflightVenvImports({\n modules: ['math', 'json', 're'],\n requireDocker: false,\n fix: 'Fix: python3 -m venv bench/.venv (verify.py only needs the stdlib — no pip install).',\n })\n if (fixturesMode) {\n await readFile(FIXTURES, 'utf8').catch((err) => {\n throw new Error(`AEC_FIXTURES=1 but ${FIXTURES} unreadable: ${err instanceof Error ? err.message : err}`)\n })\n return\n }\n const res = await fetch(`${RAW}/README.md`, { method: 'HEAD' }).catch((err) => {\n throw new Error(\n `aec-bench preflight failed reaching ${RAW}: ${err instanceof Error ? err.message : err}\\n` +\n `Fix: ensure network access to raw.githubusercontent.com, or set AEC_FIXTURES=1 to run offline.`,\n )\n })\n if (!res.ok) {\n throw new Error(\n `aec-bench preflight: ${REPO} README HEAD ${res.status}. Set AEC_FIXTURES=1 to run against committed fixtures.`,\n )\n }\n },\n\n async loadTasks(opts: LoadOptions = {}) {\n if (fixturesMode) return loadFixtures(opts)\n try {\n return await loadLive(opts)\n } catch (err) {\n // A reachability failure falls back to fixtures with an explicit warn; a\n // wrong-id / seed-only error (the loader's own throw) propagates.\n if (err instanceof Error && /fetch \\d|ENOTFOUND|getaddrinfo|network/i.test(err.message)) {\n console.warn(\n `[aec-bench] live fetch failed (${err.message.slice(0, 160)}); falling back to committed fixtures at ${FIXTURES}`,\n )\n return loadFixtures(opts)\n }\n throw err\n }\n },\n\n async goldArtifact(task: BenchTask) {\n // Gold = the task's own golden_pass.md (scores reward 1.0 through the SAME\n // verify.py the real artifact takes), proving the judge end-to-end. Tasks\n // without a golden_pass.md (non-md ground truth) have no oracle artifact.\n const meta = readMeta(task)\n return meta.goldenPassMd ?? undefined\n },\n\n async judge(task: BenchTask, artifact: string): Promise<BenchScore> {\n const meta = readMeta(task)\n // verify.py fail-closes an empty/unparseable artifact to reward 0.0 itself,\n // so we pass it straight through (no pre-judging here).\n return runVerifier(meta, artifact)\n },\n }\n}\n"],"mappings":"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","names":["records"]}
@@ -1,120 +0,0 @@
1
- import {
2
- FINAL_ANSWER_SENTINEL,
3
- allStrings,
4
- answerScoreToBenchScore,
5
- contextBlock,
6
- contextsFrom,
7
- firstString,
8
- isObject,
9
- ragAnswerOutput,
10
- readJsonRows,
11
- scoreAnswerArtifact,
12
- selectTasks,
13
- stringFrom
14
- } from "./chunk-X3BTXCJ4.js";
15
- import {
16
- benchRoot
17
- } from "./chunk-EIETHPD5.js";
18
-
19
- // src/benchmarks/open-rag-bench.ts
20
- import { readFile } from "fs/promises";
21
- import { join } from "path";
22
- var FIXTURES = join(benchRoot, "fixtures", "open-rag-bench.json");
23
- var dataFile = () => process.env.OPEN_RAG_BENCH_DATA_FILE;
24
- function rowToTask(raw, index) {
25
- if (!isObject(raw)) throw new Error(`Open RAG Bench row ${index} must be an object`);
26
- const query = firstString(raw, ["question", "query", "prompt"]);
27
- const goldAnswers = allStrings(raw, ["answer", "answers", "reference", "reference_answer", "gold"]);
28
- if (!query) throw new Error(`Open RAG Bench row ${index} missing question/query`);
29
- if (goldAnswers.length === 0) throw new Error(`Open RAG Bench row ${index} missing answer`);
30
- const contexts = contextsFrom(raw.contexts).length > 0 ? contextsFrom(raw.contexts) : contextsFrom(raw.chunks).length > 0 ? contextsFrom(raw.chunks) : contextsFrom(raw.pages);
31
- const documentId = stringFrom(raw.document_id) ?? stringFrom(raw.doc_id) ?? stringFrom(raw.pdf_id) ?? stringFrom(raw.file_name) ?? stringFrom(raw.filename) ?? "unknown";
32
- const modality = stringFrom(raw.modality) ?? stringFrom(raw.answer_modality) ?? "unknown";
33
- const id = stringFrom(raw.id) ?? stringFrom(raw.query_id) ?? `open-rag-bench-${index}`;
34
- const meta = {
35
- benchmark: "open-rag-bench",
36
- query,
37
- goldAnswers,
38
- contexts,
39
- documentId,
40
- modality
41
- };
42
- return {
43
- id,
44
- split: stringFrom(raw.split) ?? modality,
45
- prompt: [
46
- "Answer this Open RAG Bench PDF question using the supplied document context.",
47
- "Use tables, text, and image-derived notes when present.",
48
- "End with a single final line: `FINAL ANSWER: <answer>`.",
49
- "",
50
- `Question: ${query}`,
51
- `Document: ${documentId}`,
52
- `Modality: ${modality}`,
53
- contexts.length > 0 ? `
54
- Document context:
55
- ${contextBlock(contexts)}` : void 0
56
- ].filter(Boolean).join("\n"),
57
- metadata: meta
58
- };
59
- }
60
- function readMeta(task) {
61
- const md = task.metadata;
62
- if (!md || !Array.isArray(md.goldAnswers)) {
63
- throw new Error(`Open RAG Bench task ${task.id} missing metadata \u2014 loadTasks did not populate it`);
64
- }
65
- return md;
66
- }
67
- async function loadRows(path) {
68
- const rows = await readJsonRows(path);
69
- if (rows.length === 0) throw new Error(`Open RAG Bench: no rows in ${path}`);
70
- return rows;
71
- }
72
- async function loadFixtures(opts) {
73
- const rows = JSON.parse(await readFile(FIXTURES, "utf8"));
74
- console.warn(`[open-rag-bench] OPEN_RAG_BENCH_FIXTURES=1 \u2014 loading ${rows.length} adapter fixtures`);
75
- return selectTasks(rows.map(rowToTask), opts, "Open RAG Bench");
76
- }
77
- function createOpenRagBenchAdapter() {
78
- const fixturesMode = process.env.OPEN_RAG_BENCH_FIXTURES === "1";
79
- return {
80
- name: "open-rag-bench",
81
- output: ragAnswerOutput,
82
- async preflight() {
83
- if (fixturesMode) {
84
- await readFile(FIXTURES, "utf8");
85
- return;
86
- }
87
- const path = dataFile();
88
- if (!path) {
89
- throw new Error(
90
- "OPEN_RAG_BENCH_DATA_FILE is required. Fix: export vectara/open-rag-bench rows to JSONL and set OPEN_RAG_BENCH_DATA_FILE=/path/to/open-rag-bench.jsonl, or set OPEN_RAG_BENCH_FIXTURES=1 for adapter plumbing."
91
- );
92
- }
93
- await loadRows(path);
94
- },
95
- async loadTasks(opts = {}) {
96
- if (fixturesMode) return loadFixtures(opts);
97
- const path = dataFile();
98
- if (!path) throw new Error("OPEN_RAG_BENCH_DATA_FILE is required to load Open RAG Bench tasks");
99
- return selectTasks((await loadRows(path)).map(rowToTask), opts, "Open RAG Bench");
100
- },
101
- async goldArtifact(task) {
102
- return `${FINAL_ANSWER_SENTINEL} ${readMeta(task).goldAnswers[0] ?? ""}`;
103
- },
104
- async judge(task, artifact) {
105
- const meta = readMeta(task);
106
- const score = scoreAnswerArtifact(artifact, meta.goldAnswers);
107
- return answerScoreToBenchScore(score, {
108
- benchmark: meta.benchmark,
109
- documentId: meta.documentId,
110
- modality: meta.modality,
111
- contextCount: meta.contexts.length
112
- });
113
- }
114
- };
115
- }
116
-
117
- export {
118
- createOpenRagBenchAdapter
119
- };
120
- //# sourceMappingURL=chunk-BZY5QARD.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/benchmarks/open-rag-bench.ts"],"sourcesContent":["/**\n * Open RAG Bench adapter.\n *\n * This targets Vectara-style Open RAG Bench exports over PDF-derived text,\n * table, and image contexts. The deterministic judge scores final-answer\n * agreement and surfaces modality/document metadata for diagnostics.\n */\n\nimport { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { benchRoot } from './_harness'\nimport type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'\nimport {\n FINAL_ANSWER_SENTINEL,\n allStrings,\n answerScoreToBenchScore,\n contextBlock,\n contextsFrom,\n firstString,\n isObject,\n ragAnswerOutput,\n readJsonRows,\n scoreAnswerArtifact,\n selectTasks,\n stringFrom,\n type RagContext,\n} from './rag-shared'\n\nconst FIXTURES = join(benchRoot, 'fixtures', 'open-rag-bench.json')\n\ninterface OpenRagBenchMeta {\n benchmark: 'open-rag-bench'\n query: string\n goldAnswers: string[]\n contexts: RagContext[]\n documentId: string\n modality: string\n}\n\nconst dataFile = (): string | undefined => process.env.OPEN_RAG_BENCH_DATA_FILE\n\nfunction rowToTask(raw: unknown, index: number): BenchTask {\n if (!isObject(raw)) throw new Error(`Open RAG Bench row ${index} must be an object`)\n const query = firstString(raw, ['question', 'query', 'prompt'])\n const goldAnswers = allStrings(raw, ['answer', 'answers', 'reference', 'reference_answer', 'gold'])\n if (!query) throw new Error(`Open RAG Bench row ${index} missing question/query`)\n if (goldAnswers.length === 0) throw new Error(`Open RAG Bench row ${index} missing answer`)\n const contexts =\n contextsFrom(raw.contexts).length > 0\n ? contextsFrom(raw.contexts)\n : contextsFrom(raw.chunks).length > 0\n ? contextsFrom(raw.chunks)\n : contextsFrom(raw.pages)\n const documentId =\n stringFrom(raw.document_id) ??\n stringFrom(raw.doc_id) ??\n stringFrom(raw.pdf_id) ??\n stringFrom(raw.file_name) ??\n stringFrom(raw.filename) ??\n 'unknown'\n const modality = stringFrom(raw.modality) ?? stringFrom(raw.answer_modality) ?? 'unknown'\n const id = stringFrom(raw.id) ?? stringFrom(raw.query_id) ?? `open-rag-bench-${index}`\n const meta: OpenRagBenchMeta = {\n benchmark: 'open-rag-bench',\n query,\n goldAnswers,\n contexts,\n documentId,\n modality,\n }\n return {\n id,\n split: stringFrom(raw.split) ?? modality,\n prompt: [\n 'Answer this Open RAG Bench PDF question using the supplied document context.',\n 'Use tables, text, and image-derived notes when present.',\n 'End with a single final line: `FINAL ANSWER: <answer>`.',\n '',\n `Question: ${query}`,\n `Document: ${documentId}`,\n `Modality: ${modality}`,\n contexts.length > 0 ? `\\nDocument context:\\n${contextBlock(contexts)}` : undefined,\n ]\n .filter(Boolean)\n .join('\\n'),\n metadata: meta as unknown as Record<string, unknown>,\n }\n}\n\nfunction readMeta(task: BenchTask): OpenRagBenchMeta {\n const md = task.metadata\n if (!md || !Array.isArray(md.goldAnswers)) {\n throw new Error(`Open RAG Bench task ${task.id} missing metadata — loadTasks did not populate it`)\n }\n return md as unknown as OpenRagBenchMeta\n}\n\nasync function loadRows(path: string): Promise<unknown[]> {\n const rows = await readJsonRows(path)\n if (rows.length === 0) throw new Error(`Open RAG Bench: no rows in ${path}`)\n return rows\n}\n\nasync function loadFixtures(opts: LoadOptions): Promise<BenchTask[]> {\n const rows = JSON.parse(await readFile(FIXTURES, 'utf8')) as unknown[]\n console.warn(`[open-rag-bench] OPEN_RAG_BENCH_FIXTURES=1 — loading ${rows.length} adapter fixtures`)\n return selectTasks(rows.map(rowToTask), opts, 'Open RAG Bench')\n}\n\nexport function createOpenRagBenchAdapter(): BenchmarkAdapter {\n const fixturesMode = process.env.OPEN_RAG_BENCH_FIXTURES === '1'\n\n return {\n name: 'open-rag-bench',\n output: ragAnswerOutput,\n\n async preflight() {\n if (fixturesMode) {\n await readFile(FIXTURES, 'utf8')\n return\n }\n const path = dataFile()\n if (!path) {\n throw new Error(\n 'OPEN_RAG_BENCH_DATA_FILE is required. Fix: export vectara/open-rag-bench rows to JSONL and set OPEN_RAG_BENCH_DATA_FILE=/path/to/open-rag-bench.jsonl, or set OPEN_RAG_BENCH_FIXTURES=1 for adapter plumbing.',\n )\n }\n await loadRows(path)\n },\n\n async loadTasks(opts: LoadOptions = {}) {\n if (fixturesMode) return loadFixtures(opts)\n const path = dataFile()\n if (!path) throw new Error('OPEN_RAG_BENCH_DATA_FILE is required to load Open RAG Bench tasks')\n return selectTasks((await loadRows(path)).map(rowToTask), opts, 'Open RAG Bench')\n },\n\n async goldArtifact(task: BenchTask) {\n return `${FINAL_ANSWER_SENTINEL} ${readMeta(task).goldAnswers[0] ?? ''}`\n },\n\n async judge(task: BenchTask, artifact: string): Promise<BenchScore> {\n const meta = readMeta(task)\n const score = scoreAnswerArtifact(artifact, meta.goldAnswers)\n return answerScoreToBenchScore(score, {\n benchmark: meta.benchmark,\n documentId: meta.documentId,\n modality: meta.modality,\n contextCount: meta.contexts.length,\n })\n },\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,103 +0,0 @@
1
- // src/benchmarks/cadgenbench.ts
2
- import { execFile as execFile2 } from "child_process";
3
- import { mkdtemp as mkdtemp2, rm as rm2, writeFile as writeFile2 } from "fs/promises";
4
- import { tmpdir as tmpdir2 } from "os";
5
- import { join as join2 } from "path";
6
- import { promisify as promisify2 } from "util";
7
-
8
- // src/worker-build123d.ts
9
- import { execFile } from "child_process";
10
- import { existsSync, readFileSync } from "fs";
11
- import { mkdtemp, readFile, rm, writeFile } from "fs/promises";
12
- import { tmpdir } from "os";
13
- import { join } from "path";
14
- import { promisify } from "util";
15
- import { routerChatWithUsage } from "@tangle-network/agent-runtime/loops";
16
- var execFileAsync = promisify(execFile);
17
- var CGB_VENV_PY = process.env.CADGENBENCH_VENV ?? "/tmp/cgb-venv/bin/python";
18
- var CGB_DIR = process.env.CADGENBENCH_DIR ?? "/tmp/cadgenbench";
19
-
20
- // src/benchmarks/cadgenbench.ts
21
- var execFileAsync2 = promisify2(execFile2);
22
- var SCORE_PY = `
23
- import sys, json, tempfile, shutil
24
- from pathlib import Path
25
- from cadgenbench.eval.evaluate import evaluate_result
26
- cand, gt = Path(sys.argv[1]), Path(sys.argv[2])
27
- with tempfile.TemporaryDirectory() as rd, tempfile.TemporaryDirectory() as gd:
28
- rd, gd = Path(rd), Path(gd)
29
- (rd / 'result.json').write_text('{}')
30
- shutil.copy(gt, gd / 'ground_truth.step')
31
- try:
32
- evaluate_result(rd, gd, candidate_step=cand)
33
- d = json.loads((rd / 'result.json').read_text())
34
- print('CGB_SCORE ' + json.dumps({'cad_score': d.get('cad_score', 0.0), 'status': d.get('status', 'unknown')}))
35
- except Exception as e:
36
- print('CGB_SCORE ' + json.dumps({'cad_score': 0.0, 'status': 'error', 'error': str(e)[:200]}))
37
- `.trim();
38
- function fixtureTasks() {
39
- const g = join2(CGB_DIR, "tests/fixtures/geometry");
40
- return [
41
- { id: "box-10x20x30", prompt: "A rectangular solid box, 10 units wide (X), 20 units deep (Y), and 30 units tall (Z).", gtStep: join2(g, "box_10_20_30.step") },
42
- { id: "cube-10", prompt: "A cube, 10 units on every side.", gtStep: join2(g, "box_10_10_10.step") },
43
- { id: "sphere-10", prompt: "A sphere of radius 10 units, centered at the origin.", gtStep: join2(g, "sphere_10.step") }
44
- ];
45
- }
46
- function createCadGenBenchAdapter() {
47
- return {
48
- name: "cadgenbench",
49
- async preflight() {
50
- const r = await execFileAsync2(CGB_VENV_PY, ["-c", 'import cadgenbench.eval.evaluate, build123d, trimesh, manifold3d; print("ok")'], { timeout: 6e4 }).catch(
51
- (e) => ({ stdout: "", stderr: e instanceof Error ? e.message : String(e) })
52
- );
53
- if (!/ok/.test(r.stdout)) {
54
- throw new Error(
55
- `cadgenbench preflight failed (venv=${CGB_VENV_PY}): ${r.stderr.slice(0, 200)}
56
- Fix: git clone https://github.com/huggingface/cadgenbench ${CGB_DIR}; python3 -m venv $CADGENBENCH_VENV; $CADGENBENCH_VENV/bin/pip install -e ${CGB_DIR}`
57
- );
58
- }
59
- },
60
- async loadTasks(opts = {}) {
61
- let tasks = fixtureTasks();
62
- const hard = process.env.CGB_HARD_DIR;
63
- if (hard) {
64
- const { readFile: readFile2 } = await import("fs/promises");
65
- tasks = JSON.parse(await readFile2(join2(hard, "tasks.json"), "utf8"));
66
- }
67
- if (opts.ids) tasks = tasks.filter((t) => opts.ids.includes(t.id));
68
- if (opts.limit != null) tasks = tasks.slice(0, opts.limit);
69
- const meta = (gtStep) => ({ gtStep, resolveThreshold: Number(process.env.CGB_RESOLVE_THRESHOLD ?? 0.9) });
70
- return tasks.map((t) => ({ id: t.id, prompt: t.prompt, metadata: meta(t.gtStep) }));
71
- },
72
- async goldArtifact() {
73
- return void 0;
74
- },
75
- async judge(task, artifact) {
76
- const { gtStep, resolveThreshold } = task.metadata;
77
- if (!artifact.includes("ISO-10303-21")) return { resolved: false, score: 0, detail: "artifact is not a STEP file" };
78
- const dir = await mkdtemp2(join2(tmpdir2(), "cgb-judge-"));
79
- const cand = join2(dir, "candidate.step");
80
- const scorer = join2(dir, "score.py");
81
- try {
82
- await writeFile2(cand, artifact);
83
- await writeFile2(scorer, SCORE_PY);
84
- const r = await execFileAsync2("xvfb-run", ["-a", CGB_VENV_PY, scorer, cand, gtStep], { maxBuffer: 1 << 26, timeout: 18e4 }).catch(
85
- (e) => ({ stdout: e.stdout ?? "", stderr: e instanceof Error ? e.message : String(e) })
86
- );
87
- const m = /CGB_SCORE (\{.*\})/.exec(r.stdout);
88
- if (!m) return { resolved: false, score: 0, detail: `scorer produced no verdict: ${(r.stderr || r.stdout).slice(0, 160)}` };
89
- const v = JSON.parse(m[1]);
90
- const score = typeof v.cad_score === "number" ? v.cad_score : 0;
91
- return { resolved: score >= resolveThreshold, score, detail: `cad_score=${score.toFixed(3)} status=${v.status}${v.error ? ` (${v.error})` : ""}` };
92
- } finally {
93
- await rm2(dir, { recursive: true, force: true }).catch(() => {
94
- });
95
- }
96
- }
97
- };
98
- }
99
-
100
- export {
101
- createCadGenBenchAdapter
102
- };
103
- //# sourceMappingURL=chunk-C7T7WEK2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/benchmarks/cadgenbench.ts","../src/worker-build123d.ts"],"sourcesContent":["/**\n * CADGenBench adapter (huggingface/cadgenbench, Apache-2.0). Task = a part\n * description → a STEP B-rep solid (output.step). Score = the benchmark's OWN\n * deterministic geometric metric (cad_score): validity gate → PCA/ICP align to\n * the ground truth → point-cloud F1 + volume IoU + edge F1 + topology match.\n * NOT an LLM judge, NOT self-defined checks — the published CAD kernel decides.\n *\n * The official task set (private GT, server-side graded) isn't released yet, so\n * tasks here are seeded from the repo's dimension-named geometry fixtures (real\n * GT STEPs scored by the real scorer). When CADGENBENCH_DATA_DIR is set, swap\n * loadTasks to read the published fixtures' description.yaml + ground_truth.step.\n *\n * Requires the CADGenBench venv (CADGENBENCH_VENV) + clone (CADGENBENCH_DIR) +\n * xvfb (the scorer's alignment renders need a display).\n */\n\nimport { execFile } from 'node:child_process'\nimport { mkdtemp, rm, writeFile } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { promisify } from 'node:util'\nimport type { BenchScore, BenchTask, BenchmarkAdapter, LoadOptions } from './types'\nimport { CGB_DIR, CGB_VENV_PY } from '../worker-build123d'\n\nconst execFileAsync = promisify(execFile)\n\n/** Self-contained scorer wrapper (written to a temp file, run in the venv).\n * Scores a candidate STEP against a ground-truth STEP via the benchmark's own\n * evaluate_result, printing the cad_score line. */\nconst SCORE_PY = `\nimport sys, json, tempfile, shutil\nfrom pathlib import Path\nfrom cadgenbench.eval.evaluate import evaluate_result\ncand, gt = Path(sys.argv[1]), Path(sys.argv[2])\nwith tempfile.TemporaryDirectory() as rd, tempfile.TemporaryDirectory() as gd:\n rd, gd = Path(rd), Path(gd)\n (rd / 'result.json').write_text('{}')\n shutil.copy(gt, gd / 'ground_truth.step')\n try:\n evaluate_result(rd, gd, candidate_step=cand)\n d = json.loads((rd / 'result.json').read_text())\n print('CGB_SCORE ' + json.dumps({'cad_score': d.get('cad_score', 0.0), 'status': d.get('status', 'unknown')}))\n except Exception as e:\n print('CGB_SCORE ' + json.dumps({'cad_score': 0.0, 'status': 'error', 'error': str(e)[:200]}))\n`.trim()\n\ninterface CgbMeta {\n gtStep: string\n resolveThreshold: number\n}\n\n/** Fixture-seeded tasks (real GT STEPs from the repo, dim-named so the spec is\n * exact). Replaced by the published dataset when CADGENBENCH_DATA_DIR is set. */\nfunction fixtureTasks(): Array<{ id: string; prompt: string; gtStep: string }> {\n const g = join(CGB_DIR, 'tests/fixtures/geometry')\n return [\n { id: 'box-10x20x30', prompt: 'A rectangular solid box, 10 units wide (X), 20 units deep (Y), and 30 units tall (Z).', gtStep: join(g, 'box_10_20_30.step') },\n { id: 'cube-10', prompt: 'A cube, 10 units on every side.', gtStep: join(g, 'box_10_10_10.step') },\n { id: 'sphere-10', prompt: 'A sphere of radius 10 units, centered at the origin.', gtStep: join(g, 'sphere_10.step') },\n ]\n}\n\nexport function createCadGenBenchAdapter(): BenchmarkAdapter {\n return {\n name: 'cadgenbench',\n\n async preflight() {\n const r = await execFileAsync(CGB_VENV_PY, ['-c', 'import cadgenbench.eval.evaluate, build123d, trimesh, manifold3d; print(\"ok\")'], { timeout: 60_000 }).catch(\n (e) => ({ stdout: '', stderr: e instanceof Error ? e.message : String(e) }),\n )\n if (!/ok/.test(r.stdout)) {\n throw new Error(\n `cadgenbench preflight failed (venv=${CGB_VENV_PY}): ${r.stderr.slice(0, 200)}\\n` +\n `Fix: git clone https://github.com/huggingface/cadgenbench ${CGB_DIR}; python3 -m venv $CADGENBENCH_VENV; $CADGENBENCH_VENV/bin/pip install -e ${CGB_DIR}`,\n )\n }\n },\n\n async loadTasks(opts: LoadOptions = {}) {\n // CGB_HARD_DIR (a dir with tasks.json = [{id,prompt,gtStep}]) overrides the\n // trivial fixture primitives with hard multi-feature parts (real headroom).\n let tasks = fixtureTasks()\n const hard = process.env.CGB_HARD_DIR\n if (hard) {\n const { readFile } = await import('node:fs/promises')\n tasks = JSON.parse(await readFile(join(hard, 'tasks.json'), 'utf8')) as Array<{ id: string; prompt: string; gtStep: string }>\n }\n if (opts.ids) tasks = tasks.filter((t) => opts.ids!.includes(t.id))\n if (opts.limit != null) tasks = tasks.slice(0, opts.limit)\n const meta = (gtStep: string): CgbMeta => ({ gtStep, resolveThreshold: Number(process.env.CGB_RESOLVE_THRESHOLD ?? 0.9) })\n return tasks.map((t): BenchTask => ({ id: t.id, prompt: t.prompt, metadata: meta(t.gtStep) as unknown as Record<string, unknown> }))\n },\n\n async goldArtifact() {\n return undefined // GT is a STEP file scored by the kernel, not a returnable artifact\n },\n\n async judge(task: BenchTask, artifact: string): Promise<BenchScore> {\n const { gtStep, resolveThreshold } = task.metadata as unknown as CgbMeta\n if (!artifact.includes('ISO-10303-21')) return { resolved: false, score: 0, detail: 'artifact is not a STEP file' }\n const dir = await mkdtemp(join(tmpdir(), 'cgb-judge-'))\n const cand = join(dir, 'candidate.step')\n const scorer = join(dir, 'score.py')\n try {\n await writeFile(cand, artifact)\n await writeFile(scorer, SCORE_PY)\n // xvfb: the scorer's alignment step renders; needs a display.\n const r = await execFileAsync('xvfb-run', ['-a', CGB_VENV_PY, scorer, cand, gtStep], { maxBuffer: 1 << 26, timeout: 180_000 }).catch(\n (e) => ({ stdout: (e as { stdout?: string }).stdout ?? '', stderr: e instanceof Error ? e.message : String(e) }),\n )\n const m = /CGB_SCORE (\\{.*\\})/.exec(r.stdout)\n if (!m) return { resolved: false, score: 0, detail: `scorer produced no verdict: ${(r.stderr || r.stdout).slice(0, 160)}` }\n const v = JSON.parse(m[1]) as { cad_score: number; status: string; error?: string }\n const score = typeof v.cad_score === 'number' ? v.cad_score : 0\n return { resolved: score >= resolveThreshold, score, detail: `cad_score=${score.toFixed(3)} status=${v.status}${v.error ? ` (${v.error})` : ''}` }\n } finally {\n await rm(dir, { recursive: true, force: true }).catch(() => {})\n }\n },\n }\n}\n","/**\n * CADGenBench worker. The deliverable is a STEP B-rep solid (output.step). We\n * author a build123d (Python on the OpenCascade kernel) script via the router,\n * execute it in the CADGenBench venv, and read back the produced output.step —\n * exactly the reference baseline's contract. The artifact returned IS the STEP\n * text, which the CADGenBench geometric scorer grades against the ground truth.\n *\n * The build123d authoring directive is the GEPA-optimizable surface; the\n * build123d API cheat sheet (shipped in the cadgenbench package) is appended as\n * fixed reference context. Requires the CADGenBench venv (CADGENBENCH_VENV) +\n * its clone (CADGENBENCH_DIR for the cheat sheet).\n */\n\nimport { execFile } from 'node:child_process'\nimport { existsSync, readFileSync } from 'node:fs'\nimport { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { promisify } from 'node:util'\nimport type { Span } from '@tangle-network/agent-eval'\nimport type { BenchTask } from './benchmarks/types'\nimport { DEFAULT_BUILD123D_DIRECTIVE } from './directives'\nimport { runRefineLoop } from './refine-loop'\nimport { routerChatWithUsage } from '@tangle-network/agent-runtime/loops'\n\nexport { DEFAULT_BUILD123D_DIRECTIVE } from './directives'\n\nconst execFileAsync = promisify(execFile)\n\nexport const CGB_VENV_PY = process.env.CADGENBENCH_VENV ?? '/tmp/cgb-venv/bin/python'\nexport const CGB_DIR = process.env.CADGENBENCH_DIR ?? '/tmp/cadgenbench'\n\nasync function runLocal(cmd: string, args: string[], cwd: string, timeoutMs = 120_000): Promise<{ code: number; stdout: string; stderr: string }> {\n try {\n const { stdout, stderr } = await execFileAsync(cmd, args, { cwd, maxBuffer: 1 << 26, timeout: timeoutMs })\n return { code: 0, stdout, stderr }\n } catch (err) {\n const e = err as { code?: number; stdout?: string; stderr?: string; message?: string }\n return { code: typeof e.code === 'number' ? e.code : 1, stdout: e.stdout ?? '', stderr: e.stderr ?? e.message ?? String(err) }\n }\n}\n\nfunction extractPy(text: string): string {\n const fence = /```(?:python|py)?\\s*\\n([\\s\\S]*?)```/i.exec(text)\n return (fence ? fence[1] : text).trim()\n}\n\nlet _cheat: string | null = null\nfunction cheatSheet(): string {\n if (_cheat != null) return _cheat\n const p = join(CGB_DIR, 'src/cadgenbench/baseline/build123d_cheat_sheet.md')\n _cheat = existsSync(p) ? readFileSync(p, 'utf8').slice(0, 12000) : ''\n return _cheat\n}\n\nexport interface Build123dConfig {\n routerBaseUrl: string\n routerKey: string\n model: string\n rounds?: number\n /** The build123d authoring directive — the GEPA-optimizable surface. */\n directive?: string\n}\n\nexport interface Build123dShot {\n /** The produced STEP text (the artifact the CADGenBench scorer grades). */\n artifact: string\n /** The Python source the agent wrote. */\n source: string\n trace: Span[]\n usage: { input: number; output: number }\n ok: boolean\n built: boolean\n detail?: string\n}\n\n/** Author a build123d script via the router, execute it in the CADGenBench venv,\n * read back output.step. Refine on execution error / missing STEP. */\nexport async function solveBuild123dLocal(task: BenchTask, cfg: Build123dConfig): Promise<Build123dShot> {\n const rounds = Math.max(1, cfg.rounds ?? 2)\n const directive = cfg.directive ?? DEFAULT_BUILD123D_DIRECTIVE\n const sys = `${directive}\\n\\nbuild123d API reference:\\n${cheatSheet()}`\n const trace: Span[] = []\n const runId = `cadgenbench-${task.id}`\n let ts = Date.now()\n const tick = () => (ts += 1)\n const usage = { input: 0, output: 0 }\n // Carried across rounds in closures (the round Artifact is the Python source; the\n // STEP text + built flag + lastErr persist outside the loop). usage is REAL.\n let step = ''\n let built = false\n let lastErr = ''\n\n trace.push({ spanId: 's-brief', runId, kind: 'llm', name: 'brief', model: cfg.model, messages: [{ role: 'user', content: task.prompt }], startedAt: tick(), endedAt: tick(), status: 'ok' } as Span)\n\n // Migrated onto runRefineLoop: the mkdtemp scratch dir is the Ctx; built (STEP\n // produced) is the early-stop, modeled as a judge so default-decide stops the\n // loop. The round-2+ steer carries lastErr + the prior source verbatim.\n const res = await runRefineLoop<string, string>({\n rounds,\n setup: () => mkdtemp(join(tmpdir(), 'b123d-')),\n prompt: (round, history) =>\n round === 1\n ? task.prompt\n : `Your previous build123d script failed:\\n${lastErr}\\n\\nPrevious script:\\n${history[history.length - 1]?.artifact ?? ''}\\n\\nFix it so it runs in python and writes a valid output.step. Brief:\\n${task.prompt}`,\n runShot: async (user, round, dir) => {\n const scriptPath = join(dir, 'build.py')\n const stepPath = join(dir, 'output.step')\n const { content, usage: u } = await routerChatWithUsage(cfg, [\n { role: 'system', content: sys },\n { role: 'user', content: user },\n ])\n if (u) {\n usage.input += u.input\n usage.output += u.output\n }\n const source = extractPy(content)\n trace.push({ spanId: `s-author-${round}`, runId, kind: 'llm', name: `author r${round}`, model: cfg.model, messages: [{ role: 'user', content: round === 1 ? task.prompt : 'refine' }], output: content.slice(0, 600), startedAt: tick(), endedAt: tick(), status: 'ok' } as Span)\n trace.push({ spanId: `s-write-${round}`, runId, kind: 'tool', name: 'write_file', toolName: 'create_file', args: { path: 'build.py', content: source }, startedAt: tick(), endedAt: tick(), status: 'ok' } as Span)\n\n await writeFile(scriptPath, source)\n const run = await runLocal(CGB_VENV_PY, [scriptPath], dir)\n const got = existsSync(stepPath) ? await readFile(stepPath, 'utf8').catch(() => '') : ''\n built = got.includes('ISO-10303-21') && got.length > 200\n lastErr = built ? '' : `${run.stdout}\\n${run.stderr}`.trim().slice(-800) || 'no output.step written'\n if (built) step = got\n trace.push({ spanId: `s-exec-${round}`, runId, kind: 'tool', name: `build123d r${round}`, toolName: 'shell.exec', args: 'python build.py', result: (built ? 'wrote output.step' : lastErr).slice(0, 1500), startedAt: tick(), endedAt: tick(), status: built ? 'ok' : 'error', error: built ? undefined : `exit ${run.code}` } as Span)\n return { artifact: source }\n },\n judge: async () => ({ valid: built }),\n teardown: (dir) => rm(dir, { recursive: true, force: true }).then(() => {}, () => {}),\n })\n\n return {\n artifact: step,\n source: res.final.artifact,\n trace,\n usage,\n ok: res.final.artifact.trim().length > 0,\n built,\n detail: built ? 'exported output.step' : `did not produce a STEP in ${rounds} rounds${lastErr ? `; last: ${lastErr.slice(0, 140)}` : ''}`,\n }\n}\n"],"mappings":"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","names":["execFile","mkdtemp","rm","writeFile","tmpdir","join","promisify","execFileAsync","promisify","execFile","join","readFile","mkdtemp","tmpdir","writeFile","rm"]}