@tangle-network/agent-bench 0.1.0 → 0.3.6

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 (317) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/HARNESS.md +302 -0
  3. package/README.md +39 -2
  4. package/dist/adapters.d.ts +15 -0
  5. package/dist/adapters.js +43 -0
  6. package/dist/adapters.js.map +1 -0
  7. package/dist/benchmarks/_harness.d.ts +125 -0
  8. package/dist/benchmarks/_harness.js +33 -0
  9. package/dist/benchmarks/_harness.js.map +1 -0
  10. package/dist/benchmarks/aec-bench.d.ts +27 -0
  11. package/dist/benchmarks/aec-bench.js +8 -0
  12. package/dist/benchmarks/aec-bench.js.map +1 -0
  13. package/dist/benchmarks/agentbench.d.ts +16 -0
  14. package/dist/benchmarks/agentbench.js +10 -0
  15. package/dist/benchmarks/agentbench.js.map +1 -0
  16. package/dist/benchmarks/appworld.d.ts +37 -0
  17. package/dist/benchmarks/appworld.js +14 -0
  18. package/dist/benchmarks/appworld.js.map +1 -0
  19. package/dist/benchmarks/bfcl.d.ts +18 -0
  20. package/dist/benchmarks/bfcl.js +10 -0
  21. package/dist/benchmarks/bfcl.js.map +1 -0
  22. package/dist/benchmarks/cad-design.d.ts +45 -0
  23. package/dist/benchmarks/cad-design.js +7 -0
  24. package/dist/benchmarks/cad-design.js.map +1 -0
  25. package/dist/benchmarks/cadbench.d.ts +19 -0
  26. package/dist/benchmarks/cadbench.js +8 -0
  27. package/dist/benchmarks/cadbench.js.map +1 -0
  28. package/dist/benchmarks/cadgenbench.d.ts +22 -0
  29. package/dist/benchmarks/cadgenbench.js +8 -0
  30. package/dist/benchmarks/cadgenbench.js.map +1 -0
  31. package/dist/benchmarks/commit0.d.ts +31 -0
  32. package/dist/benchmarks/commit0.js +10 -0
  33. package/dist/benchmarks/commit0.js.map +1 -0
  34. package/dist/benchmarks/crag.d.ts +14 -0
  35. package/dist/benchmarks/crag.js +9 -0
  36. package/dist/benchmarks/crag.js.map +1 -0
  37. package/dist/benchmarks/dabstep.d.ts +18 -0
  38. package/dist/benchmarks/dabstep.js +10 -0
  39. package/dist/benchmarks/dabstep.js.map +1 -0
  40. package/dist/benchmarks/enterpriseops-gym.d.ts +38 -0
  41. package/dist/benchmarks/enterpriseops-gym.js +10 -0
  42. package/dist/benchmarks/enterpriseops-gym.js.map +1 -0
  43. package/dist/benchmarks/finresearchbench.d.ts +15 -0
  44. package/dist/benchmarks/finresearchbench.js +8 -0
  45. package/dist/benchmarks/finresearchbench.js.map +1 -0
  46. package/dist/benchmarks/finsearchcomp.d.ts +49 -0
  47. package/dist/benchmarks/finsearchcomp.js +7 -0
  48. package/dist/benchmarks/finsearchcomp.js.map +1 -0
  49. package/dist/benchmarks/frames.d.ts +59 -0
  50. package/dist/benchmarks/frames.js +13 -0
  51. package/dist/benchmarks/frames.js.map +1 -0
  52. package/dist/benchmarks/hotpotqa.d.ts +48 -0
  53. package/dist/benchmarks/hotpotqa.js +15 -0
  54. package/dist/benchmarks/hotpotqa.js.map +1 -0
  55. package/dist/benchmarks/humaneval.d.ts +53 -0
  56. package/dist/benchmarks/humaneval.js +15 -0
  57. package/dist/benchmarks/humaneval.js.map +1 -0
  58. package/dist/benchmarks/mind2web.d.ts +41 -0
  59. package/dist/benchmarks/mind2web.js +9 -0
  60. package/dist/benchmarks/mind2web.js.map +1 -0
  61. package/dist/benchmarks/nomiracl.d.ts +15 -0
  62. package/dist/benchmarks/nomiracl.js +9 -0
  63. package/dist/benchmarks/nomiracl.js.map +1 -0
  64. package/dist/benchmarks/open-rag-bench.d.ts +14 -0
  65. package/dist/benchmarks/open-rag-bench.js +9 -0
  66. package/dist/benchmarks/open-rag-bench.js.map +1 -0
  67. package/dist/benchmarks/programbench.d.ts +38 -0
  68. package/dist/benchmarks/programbench.js +10 -0
  69. package/dist/benchmarks/programbench.js.map +1 -0
  70. package/dist/benchmarks/rag-shared.d.ts +42 -0
  71. package/dist/benchmarks/rag-shared.js +39 -0
  72. package/dist/benchmarks/rag-shared.js.map +1 -0
  73. package/dist/benchmarks/ragbench.d.ts +16 -0
  74. package/dist/benchmarks/ragbench.js +9 -0
  75. package/dist/benchmarks/ragbench.js.map +1 -0
  76. package/dist/benchmarks/simpleqa.d.ts +64 -0
  77. package/dist/benchmarks/simpleqa.js +11 -0
  78. package/dist/benchmarks/simpleqa.js.map +1 -0
  79. package/dist/benchmarks/swe-bench.d.ts +56 -0
  80. package/dist/benchmarks/swe-bench.js +14 -0
  81. package/dist/benchmarks/swe-bench.js.map +1 -0
  82. package/dist/benchmarks/t2-ragbench.d.ts +14 -0
  83. package/dist/benchmarks/t2-ragbench.js +9 -0
  84. package/dist/benchmarks/t2-ragbench.js.map +1 -0
  85. package/dist/benchmarks/tau-bench-shared.d.ts +26 -0
  86. package/dist/benchmarks/tau-bench-shared.js +10 -0
  87. package/dist/benchmarks/tau-bench-shared.js.map +1 -0
  88. package/dist/benchmarks/tau2-bench.d.ts +7 -0
  89. package/dist/benchmarks/tau2-bench.js +11 -0
  90. package/dist/benchmarks/tau2-bench.js.map +1 -0
  91. package/dist/benchmarks/tau3-banking.d.ts +15 -0
  92. package/dist/benchmarks/tau3-banking.js +9 -0
  93. package/dist/benchmarks/tau3-banking.js.map +1 -0
  94. package/dist/benchmarks/terminal-bench.d.ts +24 -0
  95. package/dist/benchmarks/terminal-bench.js +8 -0
  96. package/dist/benchmarks/terminal-bench.js.map +1 -0
  97. package/dist/benchmarks/toollm.d.ts +16 -0
  98. package/dist/benchmarks/toollm.js +10 -0
  99. package/dist/benchmarks/toollm.js.map +1 -0
  100. package/dist/benchmarks/trata-hedge.d.ts +32 -0
  101. package/dist/benchmarks/trata-hedge.js +7 -0
  102. package/dist/benchmarks/trata-hedge.js.map +1 -0
  103. package/dist/benchmarks/types.d.ts +107 -0
  104. package/dist/benchmarks/types.js +1 -0
  105. package/dist/benchmarks/types.js.map +1 -0
  106. package/dist/benchmarks/webarena-verified.d.ts +16 -0
  107. package/dist/benchmarks/webarena-verified.js +10 -0
  108. package/dist/benchmarks/webarena-verified.js.map +1 -0
  109. package/dist/chunk-2PVVP7GN.js +197 -0
  110. package/dist/chunk-2PVVP7GN.js.map +1 -0
  111. package/dist/chunk-2XU6OGEN.js +170 -0
  112. package/dist/chunk-2XU6OGEN.js.map +1 -0
  113. package/dist/chunk-53UPUNBZ.js +325 -0
  114. package/dist/chunk-53UPUNBZ.js.map +1 -0
  115. package/dist/chunk-5SBJCB6W.js +144 -0
  116. package/dist/chunk-5SBJCB6W.js.map +1 -0
  117. package/dist/chunk-7WSD27QQ.js +118 -0
  118. package/dist/chunk-7WSD27QQ.js.map +1 -0
  119. package/dist/chunk-C7T7WEK2.js +103 -0
  120. package/dist/chunk-C7T7WEK2.js.map +1 -0
  121. package/dist/chunk-CKUVRZ2T.js +251 -0
  122. package/dist/chunk-CKUVRZ2T.js.map +1 -0
  123. package/dist/chunk-HBSWHQNJ.js +30 -0
  124. package/dist/chunk-HBSWHQNJ.js.map +1 -0
  125. package/dist/chunk-HHXFIHXC.js +116 -0
  126. package/dist/chunk-HHXFIHXC.js.map +1 -0
  127. package/dist/chunk-IFAV6KEM.js +276 -0
  128. package/dist/chunk-IFAV6KEM.js.map +1 -0
  129. package/dist/chunk-INNOYXCP.js +387 -0
  130. package/dist/chunk-INNOYXCP.js.map +1 -0
  131. package/dist/chunk-J3KDJNX2.js +182 -0
  132. package/dist/chunk-J3KDJNX2.js.map +1 -0
  133. package/dist/chunk-JRWWGMK7.js +148 -0
  134. package/dist/chunk-JRWWGMK7.js.map +1 -0
  135. package/dist/chunk-JTHWEDEW.js +32 -0
  136. package/dist/chunk-JTHWEDEW.js.map +1 -0
  137. package/dist/chunk-KDIKRJGB.js +120 -0
  138. package/dist/chunk-KDIKRJGB.js.map +1 -0
  139. package/dist/chunk-LRRD7NAG.js +301 -0
  140. package/dist/chunk-LRRD7NAG.js.map +1 -0
  141. package/dist/chunk-ODT47UAY.js +221 -0
  142. package/dist/chunk-ODT47UAY.js.map +1 -0
  143. package/dist/chunk-PA2ZKHJC.js +230 -0
  144. package/dist/chunk-PA2ZKHJC.js.map +1 -0
  145. package/dist/chunk-PPYSEKFM.js +182 -0
  146. package/dist/chunk-PPYSEKFM.js.map +1 -0
  147. package/dist/chunk-PUIRNYI7.js +189 -0
  148. package/dist/chunk-PUIRNYI7.js.map +1 -0
  149. package/dist/chunk-R36V2VP7.js +169 -0
  150. package/dist/chunk-R36V2VP7.js.map +1 -0
  151. package/dist/chunk-R67DFVLO.js +142 -0
  152. package/dist/chunk-R67DFVLO.js.map +1 -0
  153. package/dist/chunk-SEVJPLZC.js +260 -0
  154. package/dist/chunk-SEVJPLZC.js.map +1 -0
  155. package/dist/chunk-SYDW647C.js +318 -0
  156. package/dist/chunk-SYDW647C.js.map +1 -0
  157. package/dist/chunk-TBKU5XQI.js +228 -0
  158. package/dist/chunk-TBKU5XQI.js.map +1 -0
  159. package/dist/chunk-TSWPNOYM.js +147 -0
  160. package/dist/chunk-TSWPNOYM.js.map +1 -0
  161. package/dist/chunk-UAIOHCUK.js +27 -0
  162. package/dist/chunk-UAIOHCUK.js.map +1 -0
  163. package/dist/chunk-UPAMRDX4.js +233 -0
  164. package/dist/chunk-UPAMRDX4.js.map +1 -0
  165. package/dist/chunk-VQRS7VUC.js +342 -0
  166. package/dist/chunk-VQRS7VUC.js.map +1 -0
  167. package/dist/chunk-X3BTXCJ4.js +262 -0
  168. package/dist/chunk-X3BTXCJ4.js.map +1 -0
  169. package/dist/chunk-X5YKXC6V.js +211 -0
  170. package/dist/chunk-X5YKXC6V.js.map +1 -0
  171. package/dist/chunk-Y6O2OCUO.js +130 -0
  172. package/dist/chunk-Y6O2OCUO.js.map +1 -0
  173. package/dist/chunk-YCGY7UIZ.js +208 -0
  174. package/dist/chunk-YCGY7UIZ.js.map +1 -0
  175. package/dist/chunk-Z7ML6L77.js +162 -0
  176. package/dist/chunk-Z7ML6L77.js.map +1 -0
  177. package/dist/chunk-ZEWMTR5M.js +136 -0
  178. package/dist/chunk-ZEWMTR5M.js.map +1 -0
  179. package/dist/index.d.ts +355 -0
  180. package/dist/index.js +1908 -0
  181. package/dist/index.js.map +1 -0
  182. package/fixtures/aec-bench.json +18 -0
  183. package/fixtures/agentbench-dbbench.json +22 -0
  184. package/fixtures/bfcl.json +45 -0
  185. package/fixtures/commit0.json +72 -0
  186. package/fixtures/crag.json +10 -0
  187. package/fixtures/dabstep.json +22 -0
  188. package/fixtures/enterpriseops-gym.json +103 -0
  189. package/fixtures/finresearchbench.json +21 -0
  190. package/fixtures/finsearchcomp.json +66 -0
  191. package/fixtures/frames.json +26 -0
  192. package/fixtures/hotpotqa.json +182 -0
  193. package/fixtures/nomiracl.json +26 -0
  194. package/fixtures/open-rag-bench.json +16 -0
  195. package/fixtures/pier-agent/no-model-task/environment/Dockerfile +16 -0
  196. package/fixtures/pier-agent/no-model-task/environment/seed/src/status.txt +1 -0
  197. package/fixtures/pier-agent/no-model-task/instruction.md +6 -0
  198. package/fixtures/pier-agent/no-model-task/pre_artifacts.sh +6 -0
  199. package/fixtures/pier-agent/no-model-task/task.toml +35 -0
  200. package/fixtures/pier-agent/no-model-task/tests/Dockerfile +17 -0
  201. package/fixtures/pier-agent/no-model-task/tests/seed/src/status.txt +1 -0
  202. package/fixtures/pier-agent/no-model-task/tests/test.sh +19 -0
  203. package/fixtures/programbench.json +17 -0
  204. package/fixtures/ragbench.json +21 -0
  205. package/fixtures/simpleqa.json +121 -0
  206. package/fixtures/t2-ragbench.json +13 -0
  207. package/fixtures/tau2-bench.json +16 -0
  208. package/fixtures/tau3-banking.json +16 -0
  209. package/fixtures/toollm.json +28 -0
  210. package/fixtures/webarena-verified.json +20 -0
  211. package/package.json +60 -20
  212. package/pier_agents/__init__.py +18 -0
  213. package/pier_agents/candidate_contract.py +755 -0
  214. package/pier_agents/process_boundary.py +321 -0
  215. package/pier_agents/tangle_candidate.py +907 -0
  216. package/pier_agents/workspace_boundary.py +368 -0
  217. package/scripts/appworld_driver.py +359 -0
  218. package/scripts/cadbench_prepare.py +22 -0
  219. package/scripts/cadgenbench_hard_parts.py +48 -0
  220. package/scripts/clbench_codebase_judge.py +73 -0
  221. package/scripts/commit0_judge.py +170 -0
  222. package/scripts/dabstep_judge.py +42 -0
  223. package/scripts/enterpriseops_gym_judge.py +281 -0
  224. package/scripts/programbench_judge.py +120 -0
  225. package/scripts/render-gate-chart.mjs +176 -0
  226. package/scripts/run-package-tests.mjs +56 -0
  227. package/scripts/terminate-pier-trial.mts +66 -0
  228. package/scripts/trata-hedge/README.md +56 -0
  229. package/scripts/trata-hedge/run.sh +60 -0
  230. package/scripts/trata-hedge/solve.py +83 -0
  231. package/scripts/verify-packed-consumer.mjs +235 -0
  232. package/scripts/verify-pier-agent.mts +715 -0
  233. package/scripts/verify-pier-pair.mts +74 -0
  234. package/scripts/verify-pier-recovery.mts +139 -0
  235. package/src/adapters.ts +26 -0
  236. package/src/benchmarks/_harness.test.mts +178 -0
  237. package/src/benchmarks/_harness.ts +239 -16
  238. package/src/benchmarks/agentbench.ts +163 -0
  239. package/src/benchmarks/appworld.test.mts +15 -9
  240. package/src/benchmarks/bfcl.ts +346 -0
  241. package/src/benchmarks/crag.ts +137 -0
  242. package/src/benchmarks/dabstep.test.mts +70 -0
  243. package/src/benchmarks/dabstep.ts +212 -0
  244. package/src/benchmarks/external-adapters.test.mts +150 -0
  245. package/src/benchmarks/finresearchbench.ts +269 -0
  246. package/src/benchmarks/humaneval.ts +20 -8
  247. package/src/benchmarks/nomiracl.ts +180 -0
  248. package/src/benchmarks/open-rag-bench.ts +153 -0
  249. package/src/benchmarks/rag-benchmarks.test.mts +138 -0
  250. package/src/benchmarks/rag-shared.ts +327 -0
  251. package/src/benchmarks/ragbench.ts +171 -0
  252. package/src/benchmarks/swe-bench.test.mts +61 -0
  253. package/src/benchmarks/swe-bench.ts +201 -19
  254. package/src/benchmarks/t2-ragbench.ts +166 -0
  255. package/src/benchmarks/tau-bench-shared.ts +214 -0
  256. package/src/benchmarks/tau2-bench.ts +30 -0
  257. package/src/benchmarks/tau3-banking.ts +29 -0
  258. package/src/benchmarks/terminal-bench.test.mts +33 -0
  259. package/src/benchmarks/terminal-bench.ts +23 -8
  260. package/src/benchmarks/toollm.ts +254 -0
  261. package/src/benchmarks/types.ts +42 -0
  262. package/src/benchmarks/webarena-verified.ts +200 -0
  263. package/src/commit0-prereqs.sh +0 -0
  264. package/src/coordination-mcp-container-reach.mts +181 -0
  265. package/src/decoder-live.mts +1 -1
  266. package/src/examples/README.md +103 -39
  267. package/src/examples/benchmark-matrix.mts +101 -0
  268. package/src/examples/lean-proof-gate.README.md +77 -0
  269. package/src/examples/lean-proof-gate.mts +162 -0
  270. package/src/examples/lean-verify.ts +95 -0
  271. package/src/examples/lean.Dockerfile +12 -0
  272. package/src/examples/math-demo.mts +9 -7
  273. package/src/examples/strategy-demo.mts +10 -12
  274. package/src/gate.ts +3 -2
  275. package/src/hev-eval.mts +69 -0
  276. package/src/hev-improve.mts +169 -0
  277. package/src/hev-structural.mts +688 -0
  278. package/src/index.ts +73 -0
  279. package/src/mbpp-structural.mts +662 -0
  280. package/src/pier-agent.test-fixtures.mts +19 -0
  281. package/src/pier-agent.test.mts +363 -0
  282. package/src/pier-agent.ts +657 -0
  283. package/src/pier-result-grader.mjs +30 -0
  284. package/src/pier-result-grader.test.mts +62 -0
  285. package/src/pier-result-grader.ts +108 -0
  286. package/src/pier-task-outcome.test.mts +117 -0
  287. package/src/pier-task-outcome.ts +240 -0
  288. package/src/pier-trial-controller.test.mts +412 -0
  289. package/src/pier-trial-controller.ts +858 -0
  290. package/src/pier-trial-supervisor.mjs +352 -0
  291. package/src/resolve-client.ts +25 -2
  292. package/src/run-benchmarks-cli.mts +72 -0
  293. package/src/run-benchmarks-report.ts +66 -0
  294. package/src/run-benchmarks.test.mts +231 -0
  295. package/src/run-benchmarks.ts +589 -0
  296. package/src/smoke-structural-rollout.mts +393 -0
  297. package/src/swe-bench-env.test.ts +207 -0
  298. package/src/swe-bench-env.ts +554 -0
  299. package/src/swe-jail.ts +293 -0
  300. package/src/swe-self-improve.mts +84 -0
  301. package/src/swe-structural-judge-policy.test.ts +117 -0
  302. package/src/swe-structural-judge-policy.ts +133 -0
  303. package/src/swe-structural-policy.test.ts +124 -0
  304. package/src/swe-structural-policy.ts +132 -0
  305. package/src/swe-structural-provenance.test.ts +93 -0
  306. package/src/swe-structural-provenance.ts +138 -0
  307. package/src/swe-structural.mts +1260 -0
  308. package/src/swe-temp.ts +14 -0
  309. package/src/tb-container-executor.mts +234 -0
  310. package/src/tb-container-executor.test.mts +99 -0
  311. package/src/tb-supervisor-sidecar.mts +222 -0
  312. package/src/trata-gepa.mts +1 -1
  313. package/steerers/eops-itsm-population.json +1 -0
  314. package/tb_agents/opencode_refine_agent.py +117 -0
  315. package/tb_agents/opencode_router_agent.py +406 -0
  316. package/tb_agents/opencode_supervisor_agent.py +239 -0
  317. package/tb_agents/script_agent.py +66 -0
@@ -0,0 +1,180 @@
1
+ /**
2
+ * NoMIRACL adapter.
3
+ *
4
+ * NoMIRACL tests robustness to irrelevant retrieved passages. The worker does
5
+ * not generate an answer here; it classifies whether the supplied passages
6
+ * contain enough evidence to answer the query. This directly measures false
7
+ * positive / false negative behavior for RAG abstention.
8
+ */
9
+
10
+ import { readFile } from 'node:fs/promises'
11
+ import { join } from 'node:path'
12
+ import { benchRoot } from './_harness'
13
+ import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
14
+ import {
15
+ contextBlock,
16
+ contextsFrom,
17
+ firstString,
18
+ isObject,
19
+ ragAnswerOutput,
20
+ readJsonRows,
21
+ selectTasks,
22
+ stringFrom,
23
+ type RagContext,
24
+ } from './rag-shared'
25
+
26
+ const FIXTURES = join(benchRoot, 'fixtures', 'nomiracl.json')
27
+
28
+ interface NoMiraclMeta {
29
+ benchmark: 'nomiracl'
30
+ query: string
31
+ answerable: boolean
32
+ language: string
33
+ subset: string
34
+ contexts: RagContext[]
35
+ }
36
+
37
+ const dataFile = (): string | undefined => process.env.NOMIRACL_DATA_FILE
38
+
39
+ function passagesFrom(value: unknown, relevant: boolean): RagContext[] {
40
+ return contextsFrom(value).map((context) => ({ ...context, relevant }))
41
+ }
42
+
43
+ function answerableFrom(raw: Record<string, unknown>, contexts: readonly RagContext[]): boolean {
44
+ const direct = raw.answerable ?? raw.is_answerable ?? raw.has_answer ?? raw.label ?? raw.relevant
45
+ if (typeof direct === 'boolean') return direct
46
+ if (typeof direct === 'number') return direct > 0
47
+ if (typeof direct === 'string') {
48
+ const normalized = direct.toLowerCase()
49
+ if (['true', 't', 'relevant', 'answerable', 'positive', '1', 'yes'].includes(normalized)) return true
50
+ if (['false', 'f', 'non-relevant', 'non_relevant', 'unanswerable', 'negative', '0', 'no'].includes(normalized)) {
51
+ return false
52
+ }
53
+ }
54
+ return contexts.some((context) => context.relevant === true)
55
+ }
56
+
57
+ function rowToTask(raw: unknown, index: number): BenchTask {
58
+ if (!isObject(raw)) throw new Error(`NoMIRACL row ${index} must be an object`)
59
+ const query = firstString(raw, ['query', 'question'])
60
+ if (!query) throw new Error(`NoMIRACL row ${index} missing query`)
61
+ const labelledPassages = [
62
+ ...passagesFrom(raw.positive_passages, true),
63
+ ...passagesFrom(raw.negative_passages, false),
64
+ ]
65
+ const contexts =
66
+ labelledPassages.length > 0
67
+ ? labelledPassages
68
+ : contextsFrom(raw.passages).length > 0
69
+ ? contextsFrom(raw.passages)
70
+ : contextsFrom(raw.contexts).length > 0
71
+ ? contextsFrom(raw.contexts)
72
+ : contextsFrom(raw.documents)
73
+ const answerable = answerableFrom(raw, contexts)
74
+ const language = stringFrom(raw.lang) ?? stringFrom(raw.language) ?? 'unknown'
75
+ const subset = stringFrom(raw.subset) ?? (answerable ? 'relevant' : 'non-relevant')
76
+ const id = stringFrom(raw.id) ?? stringFrom(raw.query_id) ?? `nomiracl-${index}`
77
+ const meta: NoMiraclMeta = {
78
+ benchmark: 'nomiracl',
79
+ query,
80
+ answerable,
81
+ language,
82
+ subset,
83
+ contexts,
84
+ }
85
+ return {
86
+ id,
87
+ split: stringFrom(raw.split) ?? language,
88
+ prompt: [
89
+ 'Classify this NoMIRACL RAG relevance case.',
90
+ 'Return exactly one word: ANSWERABLE if at least one supplied passage contains enough evidence to answer the query, otherwise UNANSWERABLE.',
91
+ '',
92
+ `Query: ${query}`,
93
+ contexts.length > 0 ? `\nPassages:\n${contextBlock(contexts)}` : undefined,
94
+ ]
95
+ .filter(Boolean)
96
+ .join('\n'),
97
+ metadata: meta as unknown as Record<string, unknown>,
98
+ }
99
+ }
100
+
101
+ function readMeta(task: BenchTask): NoMiraclMeta {
102
+ const md = task.metadata
103
+ if (!md || typeof md.answerable !== 'boolean') {
104
+ throw new Error(`NoMIRACL task ${task.id} missing metadata — loadTasks did not populate it`)
105
+ }
106
+ return md as unknown as NoMiraclMeta
107
+ }
108
+
109
+ function parseClassification(artifact: string): boolean | null {
110
+ const normalized = artifact.toLowerCase().replace(/[^a-z0-9]+/g, ' ').trim()
111
+ if (/\bunanswerable\b|\bnot answerable\b|\bno answer\b|\bnegative\b|\bfalse\b/.test(normalized)) {
112
+ return false
113
+ }
114
+ if (/\banswerable\b|\brelevant\b|\bpositive\b|\btrue\b|\byes\b/.test(normalized)) return true
115
+ return null
116
+ }
117
+
118
+ async function loadRows(path: string): Promise<unknown[]> {
119
+ const rows = await readJsonRows(path)
120
+ if (rows.length === 0) throw new Error(`NoMIRACL: no rows in ${path}`)
121
+ return rows
122
+ }
123
+
124
+ async function loadFixtures(opts: LoadOptions): Promise<BenchTask[]> {
125
+ const rows = JSON.parse(await readFile(FIXTURES, 'utf8')) as unknown[]
126
+ console.warn(`[nomiracl] NOMIRACL_FIXTURES=1 — loading ${rows.length} adapter fixtures`)
127
+ return selectTasks(rows.map(rowToTask), opts, 'NoMIRACL')
128
+ }
129
+
130
+ export function createNoMiraclAdapter(): BenchmarkAdapter {
131
+ const fixturesMode = process.env.NOMIRACL_FIXTURES === '1'
132
+
133
+ return {
134
+ name: 'nomiracl',
135
+ output: ragAnswerOutput,
136
+
137
+ async preflight() {
138
+ if (fixturesMode) {
139
+ await readFile(FIXTURES, 'utf8')
140
+ return
141
+ }
142
+ const path = dataFile()
143
+ if (!path) {
144
+ throw new Error(
145
+ 'NOMIRACL_DATA_FILE is required. Fix: export project-miracl/nomiracl rows to JSONL and set NOMIRACL_DATA_FILE=/path/to/nomiracl.jsonl, or set NOMIRACL_FIXTURES=1 for adapter plumbing.',
146
+ )
147
+ }
148
+ await loadRows(path)
149
+ },
150
+
151
+ async loadTasks(opts: LoadOptions = {}) {
152
+ if (fixturesMode) return loadFixtures(opts)
153
+ const path = dataFile()
154
+ if (!path) throw new Error('NOMIRACL_DATA_FILE is required to load NoMIRACL tasks')
155
+ return selectTasks((await loadRows(path)).map(rowToTask), opts, 'NoMIRACL')
156
+ },
157
+
158
+ async goldArtifact(task: BenchTask) {
159
+ return readMeta(task).answerable ? 'ANSWERABLE' : 'UNANSWERABLE'
160
+ },
161
+
162
+ async judge(task: BenchTask, artifact: string): Promise<BenchScore> {
163
+ const meta = readMeta(task)
164
+ const got = parseClassification(artifact)
165
+ const resolved = got === meta.answerable
166
+ return {
167
+ resolved,
168
+ score: resolved ? 1 : 0,
169
+ detail: JSON.stringify({
170
+ benchmark: meta.benchmark,
171
+ language: meta.language,
172
+ subset: meta.subset,
173
+ expected: meta.answerable ? 'ANSWERABLE' : 'UNANSWERABLE',
174
+ got: got === null ? null : got ? 'ANSWERABLE' : 'UNANSWERABLE',
175
+ contextCount: meta.contexts.length,
176
+ }),
177
+ }
178
+ },
179
+ }
180
+ }
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Open RAG Bench adapter.
3
+ *
4
+ * This targets Vectara-style Open RAG Bench exports over PDF-derived text,
5
+ * table, and image contexts. The deterministic judge scores final-answer
6
+ * agreement and surfaces modality/document metadata for diagnostics.
7
+ */
8
+
9
+ import { readFile } from 'node:fs/promises'
10
+ import { join } from 'node:path'
11
+ import { benchRoot } from './_harness'
12
+ import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
13
+ import {
14
+ FINAL_ANSWER_SENTINEL,
15
+ allStrings,
16
+ answerScoreToBenchScore,
17
+ contextBlock,
18
+ contextsFrom,
19
+ firstString,
20
+ isObject,
21
+ ragAnswerOutput,
22
+ readJsonRows,
23
+ scoreAnswerArtifact,
24
+ selectTasks,
25
+ stringFrom,
26
+ type RagContext,
27
+ } from './rag-shared'
28
+
29
+ const FIXTURES = join(benchRoot, 'fixtures', 'open-rag-bench.json')
30
+
31
+ interface OpenRagBenchMeta {
32
+ benchmark: 'open-rag-bench'
33
+ query: string
34
+ goldAnswers: string[]
35
+ contexts: RagContext[]
36
+ documentId: string
37
+ modality: string
38
+ }
39
+
40
+ const dataFile = (): string | undefined => process.env.OPEN_RAG_BENCH_DATA_FILE
41
+
42
+ function rowToTask(raw: unknown, index: number): BenchTask {
43
+ if (!isObject(raw)) throw new Error(`Open RAG Bench row ${index} must be an object`)
44
+ const query = firstString(raw, ['question', 'query', 'prompt'])
45
+ const goldAnswers = allStrings(raw, ['answer', 'answers', 'reference', 'reference_answer', 'gold'])
46
+ if (!query) throw new Error(`Open RAG Bench row ${index} missing question/query`)
47
+ if (goldAnswers.length === 0) throw new Error(`Open RAG Bench row ${index} missing answer`)
48
+ const contexts =
49
+ contextsFrom(raw.contexts).length > 0
50
+ ? contextsFrom(raw.contexts)
51
+ : contextsFrom(raw.chunks).length > 0
52
+ ? contextsFrom(raw.chunks)
53
+ : contextsFrom(raw.pages)
54
+ const documentId =
55
+ stringFrom(raw.document_id) ??
56
+ stringFrom(raw.doc_id) ??
57
+ stringFrom(raw.pdf_id) ??
58
+ stringFrom(raw.file_name) ??
59
+ stringFrom(raw.filename) ??
60
+ 'unknown'
61
+ const modality = stringFrom(raw.modality) ?? stringFrom(raw.answer_modality) ?? 'unknown'
62
+ const id = stringFrom(raw.id) ?? stringFrom(raw.query_id) ?? `open-rag-bench-${index}`
63
+ const meta: OpenRagBenchMeta = {
64
+ benchmark: 'open-rag-bench',
65
+ query,
66
+ goldAnswers,
67
+ contexts,
68
+ documentId,
69
+ modality,
70
+ }
71
+ return {
72
+ id,
73
+ split: stringFrom(raw.split) ?? modality,
74
+ prompt: [
75
+ 'Answer this Open RAG Bench PDF question using the supplied document context.',
76
+ 'Use tables, text, and image-derived notes when present.',
77
+ 'End with a single final line: `FINAL ANSWER: <answer>`.',
78
+ '',
79
+ `Question: ${query}`,
80
+ `Document: ${documentId}`,
81
+ `Modality: ${modality}`,
82
+ contexts.length > 0 ? `\nDocument context:\n${contextBlock(contexts)}` : undefined,
83
+ ]
84
+ .filter(Boolean)
85
+ .join('\n'),
86
+ metadata: meta as unknown as Record<string, unknown>,
87
+ }
88
+ }
89
+
90
+ function readMeta(task: BenchTask): OpenRagBenchMeta {
91
+ const md = task.metadata
92
+ if (!md || !Array.isArray(md.goldAnswers)) {
93
+ throw new Error(`Open RAG Bench task ${task.id} missing metadata — loadTasks did not populate it`)
94
+ }
95
+ return md as unknown as OpenRagBenchMeta
96
+ }
97
+
98
+ async function loadRows(path: string): Promise<unknown[]> {
99
+ const rows = await readJsonRows(path)
100
+ if (rows.length === 0) throw new Error(`Open RAG Bench: no rows in ${path}`)
101
+ return rows
102
+ }
103
+
104
+ async function loadFixtures(opts: LoadOptions): Promise<BenchTask[]> {
105
+ const rows = JSON.parse(await readFile(FIXTURES, 'utf8')) as unknown[]
106
+ console.warn(`[open-rag-bench] OPEN_RAG_BENCH_FIXTURES=1 — loading ${rows.length} adapter fixtures`)
107
+ return selectTasks(rows.map(rowToTask), opts, 'Open RAG Bench')
108
+ }
109
+
110
+ export function createOpenRagBenchAdapter(): BenchmarkAdapter {
111
+ const fixturesMode = process.env.OPEN_RAG_BENCH_FIXTURES === '1'
112
+
113
+ return {
114
+ name: 'open-rag-bench',
115
+ output: ragAnswerOutput,
116
+
117
+ async preflight() {
118
+ if (fixturesMode) {
119
+ await readFile(FIXTURES, 'utf8')
120
+ return
121
+ }
122
+ const path = dataFile()
123
+ if (!path) {
124
+ throw new Error(
125
+ '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.',
126
+ )
127
+ }
128
+ await loadRows(path)
129
+ },
130
+
131
+ async loadTasks(opts: LoadOptions = {}) {
132
+ if (fixturesMode) return loadFixtures(opts)
133
+ const path = dataFile()
134
+ if (!path) throw new Error('OPEN_RAG_BENCH_DATA_FILE is required to load Open RAG Bench tasks')
135
+ return selectTasks((await loadRows(path)).map(rowToTask), opts, 'Open RAG Bench')
136
+ },
137
+
138
+ async goldArtifact(task: BenchTask) {
139
+ return `${FINAL_ANSWER_SENTINEL} ${readMeta(task).goldAnswers[0] ?? ''}`
140
+ },
141
+
142
+ async judge(task: BenchTask, artifact: string): Promise<BenchScore> {
143
+ const meta = readMeta(task)
144
+ const score = scoreAnswerArtifact(artifact, meta.goldAnswers)
145
+ return answerScoreToBenchScore(score, {
146
+ benchmark: meta.benchmark,
147
+ documentId: meta.documentId,
148
+ modality: meta.modality,
149
+ contextCount: meta.contexts.length,
150
+ })
151
+ },
152
+ }
153
+ }
@@ -0,0 +1,138 @@
1
+ import assert from 'node:assert/strict'
2
+ import { mkdtemp, rm, writeFile } from 'node:fs/promises'
3
+ import { tmpdir } from 'node:os'
4
+ import { join } from 'node:path'
5
+ import { test } from 'node:test'
6
+ import { resolveAdapter } from '../adapters'
7
+ import { createCragAdapter } from './crag'
8
+ import { createNoMiraclAdapter } from './nomiracl'
9
+ import { createOpenRagBenchAdapter } from './open-rag-bench'
10
+ import { createRagBenchAdapter } from './ragbench'
11
+ import { FINAL_ANSWER_SENTINEL, readJsonRows } from './rag-shared'
12
+ import { createT2RagBenchAdapter } from './t2-ragbench'
13
+
14
+ async function withEnv<T>(patch: Record<string, string | undefined>, fn: () => Promise<T>): Promise<T> {
15
+ const old: Record<string, string | undefined> = {}
16
+ for (const [key, value] of Object.entries(patch)) {
17
+ old[key] = process.env[key]
18
+ if (value === undefined) delete process.env[key]
19
+ else process.env[key] = value
20
+ }
21
+ try {
22
+ return await fn()
23
+ } finally {
24
+ for (const [key, value] of Object.entries(old)) {
25
+ if (value === undefined) delete process.env[key]
26
+ else process.env[key] = value
27
+ }
28
+ }
29
+ }
30
+
31
+ test('RAG benchmark adapters are registered', () => {
32
+ for (const key of ['ragbench', 'crag', 'nomiracl', 'open-rag-bench', 't2-ragbench']) {
33
+ assert.equal(resolveAdapter(key).name, key)
34
+ }
35
+ })
36
+
37
+ test('RAG JSON reader accepts object-starting JSONL exports', async () => {
38
+ const dir = await mkdtemp(join(tmpdir(), 'rag-jsonl-'))
39
+ try {
40
+ const file = join(dir, 'rows.jsonl')
41
+ await writeFile(file, '{"id":"a","question":"q1"}\n{"id":"b","question":"q2"}\n')
42
+ assert.deepEqual(await readJsonRows(file), [
43
+ { id: 'a', question: 'q1' },
44
+ { id: 'b', question: 'q2' },
45
+ ])
46
+ } finally {
47
+ await rm(dir, { recursive: true, force: true })
48
+ }
49
+ })
50
+
51
+ test('RAGBench fixture mode loads rows and scores final answers', async () => {
52
+ await withEnv({ RAGBENCH_FIXTURES: '1', RAGBENCH_DATA_FILE: undefined }, async () => {
53
+ const adapter = createRagBenchAdapter()
54
+ await adapter.preflight()
55
+ const [task] = await adapter.loadTasks({ limit: 1 })
56
+ assert.equal(task.id, 'ragbench-fixture-0')
57
+ const gold = await adapter.goldArtifact(task)
58
+ assert.equal((await adapter.judge(task, gold ?? '')).resolved, true)
59
+ assert.equal((await adapter.judge(task, `${FINAL_ANSWER_SENTINEL} 90 days`)).resolved, false)
60
+ })
61
+
62
+ await withEnv({ RAGBENCH_FIXTURES: undefined, RAGBENCH_DATA_FILE: undefined }, async () => {
63
+ await assert.rejects(() => createRagBenchAdapter().preflight(), /RAGBENCH_DATA_FILE is required/)
64
+ })
65
+ })
66
+
67
+ test('CRAG fixture mode exposes domain slices and answer judging', async () => {
68
+ await withEnv({ CRAG_FIXTURES: '1', CRAG_DATA_FILE: undefined }, async () => {
69
+ const adapter = createCragAdapter()
70
+ await adapter.preflight()
71
+ const [task] = await adapter.loadTasks({ limit: 1 })
72
+ assert.equal(task.split, 'finance')
73
+ assert.equal((await adapter.judge(task, `${FINAL_ANSWER_SENTINEL} 12.4 billion dollars`)).score, 1)
74
+ assert.equal((await adapter.judge(task, `${FINAL_ANSWER_SENTINEL} 9 billion dollars`)).resolved, false)
75
+ })
76
+
77
+ await withEnv({ CRAG_FIXTURES: undefined, CRAG_DATA_FILE: undefined }, async () => {
78
+ await assert.rejects(() => createCragAdapter().preflight(), /CRAG_DATA_FILE is required/)
79
+ })
80
+ })
81
+
82
+ test('NoMIRACL fixture mode scores answerable and unanswerable classifications', async () => {
83
+ await withEnv({ NOMIRACL_FIXTURES: '1', NOMIRACL_DATA_FILE: undefined }, async () => {
84
+ const adapter = createNoMiraclAdapter()
85
+ await adapter.preflight()
86
+ const tasks = await adapter.loadTasks({})
87
+ const relevant = tasks.find((task) => task.id === 'nomiracl-fixture-relevant')
88
+ const nonRelevant = tasks.find((task) => task.id === 'nomiracl-fixture-non-relevant')
89
+ assert.ok(relevant)
90
+ assert.ok(nonRelevant)
91
+ assert.equal((await adapter.judge(relevant, 'ANSWERABLE')).score, 1)
92
+ assert.equal((await adapter.judge(nonRelevant, 'UNANSWERABLE')).score, 1)
93
+ assert.equal((await adapter.judge(nonRelevant, 'ANSWERABLE')).score, 0)
94
+ })
95
+
96
+ await withEnv({ NOMIRACL_FIXTURES: undefined, NOMIRACL_DATA_FILE: undefined }, async () => {
97
+ await assert.rejects(() => createNoMiraclAdapter().preflight(), /NOMIRACL_DATA_FILE is required/)
98
+ })
99
+ })
100
+
101
+ test('Open RAG Bench fixture mode keeps PDF modality metadata and scores answers', async () => {
102
+ await withEnv(
103
+ { OPEN_RAG_BENCH_FIXTURES: '1', OPEN_RAG_BENCH_DATA_FILE: undefined },
104
+ async () => {
105
+ const adapter = createOpenRagBenchAdapter()
106
+ await adapter.preflight()
107
+ const [task] = await adapter.loadTasks({ limit: 1 })
108
+ assert.equal(task.split, 'table')
109
+ assert.equal((await adapter.judge(task, `${FINAL_ANSWER_SENTINEL} Hybrid BM25`)).resolved, true)
110
+ assert.equal((await adapter.judge(task, `${FINAL_ANSWER_SENTINEL} Dense`)).resolved, false)
111
+ },
112
+ )
113
+
114
+ await withEnv(
115
+ { OPEN_RAG_BENCH_FIXTURES: undefined, OPEN_RAG_BENCH_DATA_FILE: undefined },
116
+ async () => {
117
+ await assert.rejects(
118
+ () => createOpenRagBenchAdapter().preflight(),
119
+ /OPEN_RAG_BENCH_DATA_FILE is required/,
120
+ )
121
+ },
122
+ )
123
+ })
124
+
125
+ test('T2-RAGBench fixture mode scores numeric text-table answers', async () => {
126
+ await withEnv({ T2_RAGBENCH_FIXTURES: '1', T2_RAGBENCH_DATA_FILE: undefined }, async () => {
127
+ const adapter = createT2RagBenchAdapter()
128
+ await adapter.preflight()
129
+ const [task] = await adapter.loadTasks({ limit: 1 })
130
+ assert.equal(task.split, 'finqa')
131
+ assert.equal((await adapter.judge(task, `${FINAL_ANSWER_SENTINEL} 12.0 percent`)).resolved, true)
132
+ assert.equal((await adapter.judge(task, `${FINAL_ANSWER_SENTINEL} 8 percent`)).resolved, false)
133
+ })
134
+
135
+ await withEnv({ T2_RAGBENCH_FIXTURES: undefined, T2_RAGBENCH_DATA_FILE: undefined }, async () => {
136
+ await assert.rejects(() => createT2RagBenchAdapter().preflight(), /T2_RAGBENCH_DATA_FILE is required/)
137
+ })
138
+ })