@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.
- package/CHANGELOG.md +23 -0
- package/HARNESS.md +302 -0
- package/README.md +39 -2
- package/dist/adapters.d.ts +15 -0
- package/dist/adapters.js +43 -0
- package/dist/adapters.js.map +1 -0
- package/dist/benchmarks/_harness.d.ts +125 -0
- package/dist/benchmarks/_harness.js +33 -0
- package/dist/benchmarks/_harness.js.map +1 -0
- package/dist/benchmarks/aec-bench.d.ts +27 -0
- package/dist/benchmarks/aec-bench.js +8 -0
- package/dist/benchmarks/aec-bench.js.map +1 -0
- package/dist/benchmarks/agentbench.d.ts +16 -0
- package/dist/benchmarks/agentbench.js +10 -0
- package/dist/benchmarks/agentbench.js.map +1 -0
- package/dist/benchmarks/appworld.d.ts +37 -0
- package/dist/benchmarks/appworld.js +14 -0
- package/dist/benchmarks/appworld.js.map +1 -0
- package/dist/benchmarks/bfcl.d.ts +18 -0
- package/dist/benchmarks/bfcl.js +10 -0
- package/dist/benchmarks/bfcl.js.map +1 -0
- package/dist/benchmarks/cad-design.d.ts +45 -0
- package/dist/benchmarks/cad-design.js +7 -0
- package/dist/benchmarks/cad-design.js.map +1 -0
- package/dist/benchmarks/cadbench.d.ts +19 -0
- package/dist/benchmarks/cadbench.js +8 -0
- package/dist/benchmarks/cadbench.js.map +1 -0
- package/dist/benchmarks/cadgenbench.d.ts +22 -0
- package/dist/benchmarks/cadgenbench.js +8 -0
- package/dist/benchmarks/cadgenbench.js.map +1 -0
- package/dist/benchmarks/commit0.d.ts +31 -0
- package/dist/benchmarks/commit0.js +10 -0
- package/dist/benchmarks/commit0.js.map +1 -0
- package/dist/benchmarks/crag.d.ts +14 -0
- package/dist/benchmarks/crag.js +9 -0
- package/dist/benchmarks/crag.js.map +1 -0
- package/dist/benchmarks/dabstep.d.ts +18 -0
- package/dist/benchmarks/dabstep.js +10 -0
- package/dist/benchmarks/dabstep.js.map +1 -0
- package/dist/benchmarks/enterpriseops-gym.d.ts +38 -0
- package/dist/benchmarks/enterpriseops-gym.js +10 -0
- package/dist/benchmarks/enterpriseops-gym.js.map +1 -0
- package/dist/benchmarks/finresearchbench.d.ts +15 -0
- package/dist/benchmarks/finresearchbench.js +8 -0
- package/dist/benchmarks/finresearchbench.js.map +1 -0
- package/dist/benchmarks/finsearchcomp.d.ts +49 -0
- package/dist/benchmarks/finsearchcomp.js +7 -0
- package/dist/benchmarks/finsearchcomp.js.map +1 -0
- package/dist/benchmarks/frames.d.ts +59 -0
- package/dist/benchmarks/frames.js +13 -0
- package/dist/benchmarks/frames.js.map +1 -0
- package/dist/benchmarks/hotpotqa.d.ts +48 -0
- package/dist/benchmarks/hotpotqa.js +15 -0
- package/dist/benchmarks/hotpotqa.js.map +1 -0
- package/dist/benchmarks/humaneval.d.ts +53 -0
- package/dist/benchmarks/humaneval.js +15 -0
- package/dist/benchmarks/humaneval.js.map +1 -0
- package/dist/benchmarks/mind2web.d.ts +41 -0
- package/dist/benchmarks/mind2web.js +9 -0
- package/dist/benchmarks/mind2web.js.map +1 -0
- package/dist/benchmarks/nomiracl.d.ts +15 -0
- package/dist/benchmarks/nomiracl.js +9 -0
- package/dist/benchmarks/nomiracl.js.map +1 -0
- package/dist/benchmarks/open-rag-bench.d.ts +14 -0
- package/dist/benchmarks/open-rag-bench.js +9 -0
- package/dist/benchmarks/open-rag-bench.js.map +1 -0
- package/dist/benchmarks/programbench.d.ts +38 -0
- package/dist/benchmarks/programbench.js +10 -0
- package/dist/benchmarks/programbench.js.map +1 -0
- package/dist/benchmarks/rag-shared.d.ts +42 -0
- package/dist/benchmarks/rag-shared.js +39 -0
- package/dist/benchmarks/rag-shared.js.map +1 -0
- package/dist/benchmarks/ragbench.d.ts +16 -0
- package/dist/benchmarks/ragbench.js +9 -0
- package/dist/benchmarks/ragbench.js.map +1 -0
- package/dist/benchmarks/simpleqa.d.ts +64 -0
- package/dist/benchmarks/simpleqa.js +11 -0
- package/dist/benchmarks/simpleqa.js.map +1 -0
- package/dist/benchmarks/swe-bench.d.ts +56 -0
- package/dist/benchmarks/swe-bench.js +14 -0
- package/dist/benchmarks/swe-bench.js.map +1 -0
- package/dist/benchmarks/t2-ragbench.d.ts +14 -0
- package/dist/benchmarks/t2-ragbench.js +9 -0
- package/dist/benchmarks/t2-ragbench.js.map +1 -0
- package/dist/benchmarks/tau-bench-shared.d.ts +26 -0
- package/dist/benchmarks/tau-bench-shared.js +10 -0
- package/dist/benchmarks/tau-bench-shared.js.map +1 -0
- package/dist/benchmarks/tau2-bench.d.ts +7 -0
- package/dist/benchmarks/tau2-bench.js +11 -0
- package/dist/benchmarks/tau2-bench.js.map +1 -0
- package/dist/benchmarks/tau3-banking.d.ts +15 -0
- package/dist/benchmarks/tau3-banking.js +9 -0
- package/dist/benchmarks/tau3-banking.js.map +1 -0
- package/dist/benchmarks/terminal-bench.d.ts +24 -0
- package/dist/benchmarks/terminal-bench.js +8 -0
- package/dist/benchmarks/terminal-bench.js.map +1 -0
- package/dist/benchmarks/toollm.d.ts +16 -0
- package/dist/benchmarks/toollm.js +10 -0
- package/dist/benchmarks/toollm.js.map +1 -0
- package/dist/benchmarks/trata-hedge.d.ts +32 -0
- package/dist/benchmarks/trata-hedge.js +7 -0
- package/dist/benchmarks/trata-hedge.js.map +1 -0
- package/dist/benchmarks/types.d.ts +107 -0
- package/dist/benchmarks/types.js +1 -0
- package/dist/benchmarks/types.js.map +1 -0
- package/dist/benchmarks/webarena-verified.d.ts +16 -0
- package/dist/benchmarks/webarena-verified.js +10 -0
- package/dist/benchmarks/webarena-verified.js.map +1 -0
- package/dist/chunk-2PVVP7GN.js +197 -0
- package/dist/chunk-2PVVP7GN.js.map +1 -0
- package/dist/chunk-2XU6OGEN.js +170 -0
- package/dist/chunk-2XU6OGEN.js.map +1 -0
- package/dist/chunk-53UPUNBZ.js +325 -0
- package/dist/chunk-53UPUNBZ.js.map +1 -0
- package/dist/chunk-5SBJCB6W.js +144 -0
- package/dist/chunk-5SBJCB6W.js.map +1 -0
- package/dist/chunk-7WSD27QQ.js +118 -0
- package/dist/chunk-7WSD27QQ.js.map +1 -0
- package/dist/chunk-C7T7WEK2.js +103 -0
- package/dist/chunk-C7T7WEK2.js.map +1 -0
- package/dist/chunk-CKUVRZ2T.js +251 -0
- package/dist/chunk-CKUVRZ2T.js.map +1 -0
- package/dist/chunk-HBSWHQNJ.js +30 -0
- package/dist/chunk-HBSWHQNJ.js.map +1 -0
- package/dist/chunk-HHXFIHXC.js +116 -0
- package/dist/chunk-HHXFIHXC.js.map +1 -0
- package/dist/chunk-IFAV6KEM.js +276 -0
- package/dist/chunk-IFAV6KEM.js.map +1 -0
- package/dist/chunk-INNOYXCP.js +387 -0
- package/dist/chunk-INNOYXCP.js.map +1 -0
- package/dist/chunk-J3KDJNX2.js +182 -0
- package/dist/chunk-J3KDJNX2.js.map +1 -0
- package/dist/chunk-JRWWGMK7.js +148 -0
- package/dist/chunk-JRWWGMK7.js.map +1 -0
- package/dist/chunk-JTHWEDEW.js +32 -0
- package/dist/chunk-JTHWEDEW.js.map +1 -0
- package/dist/chunk-KDIKRJGB.js +120 -0
- package/dist/chunk-KDIKRJGB.js.map +1 -0
- package/dist/chunk-LRRD7NAG.js +301 -0
- package/dist/chunk-LRRD7NAG.js.map +1 -0
- package/dist/chunk-ODT47UAY.js +221 -0
- package/dist/chunk-ODT47UAY.js.map +1 -0
- package/dist/chunk-PA2ZKHJC.js +230 -0
- package/dist/chunk-PA2ZKHJC.js.map +1 -0
- package/dist/chunk-PPYSEKFM.js +182 -0
- package/dist/chunk-PPYSEKFM.js.map +1 -0
- package/dist/chunk-PUIRNYI7.js +189 -0
- package/dist/chunk-PUIRNYI7.js.map +1 -0
- package/dist/chunk-R36V2VP7.js +169 -0
- package/dist/chunk-R36V2VP7.js.map +1 -0
- package/dist/chunk-R67DFVLO.js +142 -0
- package/dist/chunk-R67DFVLO.js.map +1 -0
- package/dist/chunk-SEVJPLZC.js +260 -0
- package/dist/chunk-SEVJPLZC.js.map +1 -0
- package/dist/chunk-SYDW647C.js +318 -0
- package/dist/chunk-SYDW647C.js.map +1 -0
- package/dist/chunk-TBKU5XQI.js +228 -0
- package/dist/chunk-TBKU5XQI.js.map +1 -0
- package/dist/chunk-TSWPNOYM.js +147 -0
- package/dist/chunk-TSWPNOYM.js.map +1 -0
- package/dist/chunk-UAIOHCUK.js +27 -0
- package/dist/chunk-UAIOHCUK.js.map +1 -0
- package/dist/chunk-UPAMRDX4.js +233 -0
- package/dist/chunk-UPAMRDX4.js.map +1 -0
- package/dist/chunk-VQRS7VUC.js +342 -0
- package/dist/chunk-VQRS7VUC.js.map +1 -0
- package/dist/chunk-X3BTXCJ4.js +262 -0
- package/dist/chunk-X3BTXCJ4.js.map +1 -0
- package/dist/chunk-X5YKXC6V.js +211 -0
- package/dist/chunk-X5YKXC6V.js.map +1 -0
- package/dist/chunk-Y6O2OCUO.js +130 -0
- package/dist/chunk-Y6O2OCUO.js.map +1 -0
- package/dist/chunk-YCGY7UIZ.js +208 -0
- package/dist/chunk-YCGY7UIZ.js.map +1 -0
- package/dist/chunk-Z7ML6L77.js +162 -0
- package/dist/chunk-Z7ML6L77.js.map +1 -0
- package/dist/chunk-ZEWMTR5M.js +136 -0
- package/dist/chunk-ZEWMTR5M.js.map +1 -0
- package/dist/index.d.ts +355 -0
- package/dist/index.js +1908 -0
- package/dist/index.js.map +1 -0
- package/fixtures/aec-bench.json +18 -0
- package/fixtures/agentbench-dbbench.json +22 -0
- package/fixtures/bfcl.json +45 -0
- package/fixtures/commit0.json +72 -0
- package/fixtures/crag.json +10 -0
- package/fixtures/dabstep.json +22 -0
- package/fixtures/enterpriseops-gym.json +103 -0
- package/fixtures/finresearchbench.json +21 -0
- package/fixtures/finsearchcomp.json +66 -0
- package/fixtures/frames.json +26 -0
- package/fixtures/hotpotqa.json +182 -0
- package/fixtures/nomiracl.json +26 -0
- package/fixtures/open-rag-bench.json +16 -0
- package/fixtures/pier-agent/no-model-task/environment/Dockerfile +16 -0
- package/fixtures/pier-agent/no-model-task/environment/seed/src/status.txt +1 -0
- package/fixtures/pier-agent/no-model-task/instruction.md +6 -0
- package/fixtures/pier-agent/no-model-task/pre_artifacts.sh +6 -0
- package/fixtures/pier-agent/no-model-task/task.toml +35 -0
- package/fixtures/pier-agent/no-model-task/tests/Dockerfile +17 -0
- package/fixtures/pier-agent/no-model-task/tests/seed/src/status.txt +1 -0
- package/fixtures/pier-agent/no-model-task/tests/test.sh +19 -0
- package/fixtures/programbench.json +17 -0
- package/fixtures/ragbench.json +21 -0
- package/fixtures/simpleqa.json +121 -0
- package/fixtures/t2-ragbench.json +13 -0
- package/fixtures/tau2-bench.json +16 -0
- package/fixtures/tau3-banking.json +16 -0
- package/fixtures/toollm.json +28 -0
- package/fixtures/webarena-verified.json +20 -0
- package/package.json +60 -20
- package/pier_agents/__init__.py +18 -0
- package/pier_agents/candidate_contract.py +755 -0
- package/pier_agents/process_boundary.py +321 -0
- package/pier_agents/tangle_candidate.py +907 -0
- package/pier_agents/workspace_boundary.py +368 -0
- package/scripts/appworld_driver.py +359 -0
- package/scripts/cadbench_prepare.py +22 -0
- package/scripts/cadgenbench_hard_parts.py +48 -0
- package/scripts/clbench_codebase_judge.py +73 -0
- package/scripts/commit0_judge.py +170 -0
- package/scripts/dabstep_judge.py +42 -0
- package/scripts/enterpriseops_gym_judge.py +281 -0
- package/scripts/programbench_judge.py +120 -0
- package/scripts/render-gate-chart.mjs +176 -0
- package/scripts/run-package-tests.mjs +56 -0
- package/scripts/terminate-pier-trial.mts +66 -0
- package/scripts/trata-hedge/README.md +56 -0
- package/scripts/trata-hedge/run.sh +60 -0
- package/scripts/trata-hedge/solve.py +83 -0
- package/scripts/verify-packed-consumer.mjs +235 -0
- package/scripts/verify-pier-agent.mts +715 -0
- package/scripts/verify-pier-pair.mts +74 -0
- package/scripts/verify-pier-recovery.mts +139 -0
- package/src/adapters.ts +26 -0
- package/src/benchmarks/_harness.test.mts +178 -0
- package/src/benchmarks/_harness.ts +239 -16
- package/src/benchmarks/agentbench.ts +163 -0
- package/src/benchmarks/appworld.test.mts +15 -9
- package/src/benchmarks/bfcl.ts +346 -0
- package/src/benchmarks/crag.ts +137 -0
- package/src/benchmarks/dabstep.test.mts +70 -0
- package/src/benchmarks/dabstep.ts +212 -0
- package/src/benchmarks/external-adapters.test.mts +150 -0
- package/src/benchmarks/finresearchbench.ts +269 -0
- package/src/benchmarks/humaneval.ts +20 -8
- package/src/benchmarks/nomiracl.ts +180 -0
- package/src/benchmarks/open-rag-bench.ts +153 -0
- package/src/benchmarks/rag-benchmarks.test.mts +138 -0
- package/src/benchmarks/rag-shared.ts +327 -0
- package/src/benchmarks/ragbench.ts +171 -0
- package/src/benchmarks/swe-bench.test.mts +61 -0
- package/src/benchmarks/swe-bench.ts +201 -19
- package/src/benchmarks/t2-ragbench.ts +166 -0
- package/src/benchmarks/tau-bench-shared.ts +214 -0
- package/src/benchmarks/tau2-bench.ts +30 -0
- package/src/benchmarks/tau3-banking.ts +29 -0
- package/src/benchmarks/terminal-bench.test.mts +33 -0
- package/src/benchmarks/terminal-bench.ts +23 -8
- package/src/benchmarks/toollm.ts +254 -0
- package/src/benchmarks/types.ts +42 -0
- package/src/benchmarks/webarena-verified.ts +200 -0
- package/src/commit0-prereqs.sh +0 -0
- package/src/coordination-mcp-container-reach.mts +181 -0
- package/src/decoder-live.mts +1 -1
- package/src/examples/README.md +103 -39
- package/src/examples/benchmark-matrix.mts +101 -0
- package/src/examples/lean-proof-gate.README.md +77 -0
- package/src/examples/lean-proof-gate.mts +162 -0
- package/src/examples/lean-verify.ts +95 -0
- package/src/examples/lean.Dockerfile +12 -0
- package/src/examples/math-demo.mts +9 -7
- package/src/examples/strategy-demo.mts +10 -12
- package/src/gate.ts +3 -2
- package/src/hev-eval.mts +69 -0
- package/src/hev-improve.mts +169 -0
- package/src/hev-structural.mts +688 -0
- package/src/index.ts +73 -0
- package/src/mbpp-structural.mts +662 -0
- package/src/pier-agent.test-fixtures.mts +19 -0
- package/src/pier-agent.test.mts +363 -0
- package/src/pier-agent.ts +657 -0
- package/src/pier-result-grader.mjs +30 -0
- package/src/pier-result-grader.test.mts +62 -0
- package/src/pier-result-grader.ts +108 -0
- package/src/pier-task-outcome.test.mts +117 -0
- package/src/pier-task-outcome.ts +240 -0
- package/src/pier-trial-controller.test.mts +412 -0
- package/src/pier-trial-controller.ts +858 -0
- package/src/pier-trial-supervisor.mjs +352 -0
- package/src/resolve-client.ts +25 -2
- package/src/run-benchmarks-cli.mts +72 -0
- package/src/run-benchmarks-report.ts +66 -0
- package/src/run-benchmarks.test.mts +231 -0
- package/src/run-benchmarks.ts +589 -0
- package/src/smoke-structural-rollout.mts +393 -0
- package/src/swe-bench-env.test.ts +207 -0
- package/src/swe-bench-env.ts +554 -0
- package/src/swe-jail.ts +293 -0
- package/src/swe-self-improve.mts +84 -0
- package/src/swe-structural-judge-policy.test.ts +117 -0
- package/src/swe-structural-judge-policy.ts +133 -0
- package/src/swe-structural-policy.test.ts +124 -0
- package/src/swe-structural-policy.ts +132 -0
- package/src/swe-structural-provenance.test.ts +93 -0
- package/src/swe-structural-provenance.ts +138 -0
- package/src/swe-structural.mts +1260 -0
- package/src/swe-temp.ts +14 -0
- package/src/tb-container-executor.mts +234 -0
- package/src/tb-container-executor.test.mts +99 -0
- package/src/tb-supervisor-sidecar.mts +222 -0
- package/src/trata-gepa.mts +1 -1
- package/steerers/eops-itsm-population.json +1 -0
- package/tb_agents/opencode_refine_agent.py +117 -0
- package/tb_agents/opencode_router_agent.py +406 -0
- package/tb_agents/opencode_supervisor_agent.py +239 -0
- 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
|
+
})
|