@tangle-network/agent-bench 0.4.0 → 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.
- package/CHANGELOG.md +15 -0
- package/dist/adapters.d.ts +4 -11
- package/dist/adapters.js +78 -41
- package/dist/adapters.js.map +1 -1
- package/dist/benchmarks/_harness.d.ts +51 -66
- package/dist/benchmarks/_harness.js +329 -31
- package/dist/benchmarks/_harness.js.map +1 -1
- package/dist/benchmarks/aec-bench.d.ts +4 -25
- package/dist/benchmarks/aec-bench.js +242 -7
- package/dist/benchmarks/aec-bench.js.map +1 -1
- package/dist/benchmarks/agentbench.d.ts +5 -13
- package/dist/benchmarks/agentbench.js +114 -9
- package/dist/benchmarks/agentbench.js.map +1 -1
- package/dist/benchmarks/appworld.d.ts +9 -29
- package/dist/benchmarks/appworld.js +317 -12
- package/dist/benchmarks/appworld.js.map +1 -1
- package/dist/benchmarks/bfcl.d.ts +5 -15
- package/dist/benchmarks/bfcl.js +264 -9
- package/dist/benchmarks/bfcl.js.map +1 -1
- package/dist/benchmarks/cad-design.d.ts +16 -41
- package/dist/benchmarks/cad-design.js +512 -6
- package/dist/benchmarks/cad-design.js.map +1 -1
- package/dist/benchmarks/cadbench.d.ts +4 -17
- package/dist/benchmarks/cadbench.js +2 -8
- package/dist/benchmarks/cadgenbench.d.ts +4 -20
- package/dist/benchmarks/cadgenbench.js +2 -8
- package/dist/benchmarks/commit0.d.ts +5 -27
- package/dist/benchmarks/commit0.js +187 -9
- package/dist/benchmarks/commit0.js.map +1 -1
- package/dist/benchmarks/crag.d.ts +4 -12
- package/dist/benchmarks/crag.js +110 -8
- package/dist/benchmarks/crag.js.map +1 -1
- package/dist/benchmarks/dabstep.d.ts +5 -15
- package/dist/benchmarks/dabstep.js +177 -9
- package/dist/benchmarks/dabstep.js.map +1 -1
- package/dist/benchmarks/enterpriseops-gym.d.ts +5 -34
- package/dist/benchmarks/enterpriseops-gym.js +236 -9
- package/dist/benchmarks/enterpriseops-gym.js.map +1 -1
- package/dist/benchmarks/finresearchbench.d.ts +4 -13
- package/dist/benchmarks/finresearchbench.js +218 -7
- package/dist/benchmarks/finresearchbench.js.map +1 -1
- package/dist/benchmarks/finsearchcomp.d.ts +8 -39
- package/dist/benchmarks/finsearchcomp.js +267 -6
- package/dist/benchmarks/finsearchcomp.js.map +1 -1
- package/dist/benchmarks/frames.d.ts +15 -37
- package/dist/benchmarks/frames.js +408 -11
- package/dist/benchmarks/frames.js.map +1 -1
- package/dist/benchmarks/hotpotqa.d.ts +4 -24
- package/dist/benchmarks/hotpotqa.js +250 -14
- package/dist/benchmarks/hotpotqa.js.map +1 -1
- package/dist/benchmarks/humaneval.d.ts +19 -37
- package/dist/benchmarks/humaneval.js +279 -16
- package/dist/benchmarks/humaneval.js.map +1 -1
- package/dist/benchmarks/mind2web.d.ts +7 -34
- package/dist/benchmarks/mind2web.js +257 -8
- package/dist/benchmarks/mind2web.js.map +1 -1
- package/dist/benchmarks/nomiracl.d.ts +4 -13
- package/dist/benchmarks/nomiracl.js +146 -8
- package/dist/benchmarks/nomiracl.js.map +1 -1
- package/dist/benchmarks/open-rag-bench.d.ts +4 -12
- package/dist/benchmarks/open-rag-bench.js +110 -8
- package/dist/benchmarks/open-rag-bench.js.map +1 -1
- package/dist/benchmarks/programbench.d.ts +5 -29
- package/dist/benchmarks/programbench.js +161 -9
- package/dist/benchmarks/programbench.js.map +1 -1
- package/dist/benchmarks/rag-shared.d.ts +21 -20
- package/dist/benchmarks/rag-shared.js +245 -38
- package/dist/benchmarks/rag-shared.js.map +1 -1
- package/dist/benchmarks/ragbench.d.ts +4 -14
- package/dist/benchmarks/ragbench.js +127 -8
- package/dist/benchmarks/ragbench.js.map +1 -1
- package/dist/benchmarks/simpleqa.d.ts +17 -44
- package/dist/benchmarks/simpleqa.js +293 -10
- package/dist/benchmarks/simpleqa.js.map +1 -1
- package/dist/benchmarks/swe-bench.d.ts +23 -36
- package/dist/benchmarks/swe-bench.js +234 -13
- package/dist/benchmarks/swe-bench.js.map +1 -1
- package/dist/benchmarks/t2-ragbench.d.ts +4 -12
- package/dist/benchmarks/t2-ragbench.js +118 -8
- package/dist/benchmarks/t2-ragbench.js.map +1 -1
- package/dist/benchmarks/tau-bench-shared.d.ts +14 -22
- package/dist/benchmarks/tau-bench-shared.js +169 -9
- package/dist/benchmarks/tau-bench-shared.js.map +1 -1
- package/dist/benchmarks/tau2-bench.d.ts +5 -5
- package/dist/benchmarks/tau2-bench.js +28 -10
- package/dist/benchmarks/tau2-bench.js.map +1 -1
- package/dist/benchmarks/tau3-banking.d.ts +4 -13
- package/dist/benchmarks/tau3-banking.js +28 -8
- package/dist/benchmarks/tau3-banking.js.map +1 -1
- package/dist/benchmarks/terminal-bench.d.ts +4 -22
- package/dist/benchmarks/terminal-bench.js +140 -7
- package/dist/benchmarks/terminal-bench.js.map +1 -1
- package/dist/benchmarks/toollm.d.ts +5 -13
- package/dist/benchmarks/toollm.js +184 -9
- package/dist/benchmarks/toollm.js.map +1 -1
- package/dist/benchmarks/trata-hedge.d.ts +4 -30
- package/dist/benchmarks/trata-hedge.js +336 -6
- package/dist/benchmarks/trata-hedge.js.map +1 -1
- package/dist/benchmarks/types.d.ts +85 -94
- package/dist/benchmarks/types.js +1 -1
- package/dist/benchmarks/webarena-verified.d.ts +5 -13
- package/dist/benchmarks/webarena-verified.js +152 -9
- package/dist/benchmarks/webarena-verified.js.map +1 -1
- package/dist/cadbench-DpQWZHp4.js +285 -0
- package/dist/cadbench-DpQWZHp4.js.map +1 -0
- package/dist/cadgenbench-DRhczfsG.js +151 -0
- package/dist/cadgenbench-DRhczfsG.js.map +1 -0
- package/dist/index.d.ts +245 -293
- package/dist/index.js +1669 -1791
- package/dist/index.js.map +1 -1
- package/package.json +17 -14
- package/pier_agents/candidate_contract.py +238 -24
- package/pier_agents/tangle_candidate.py +75 -5
- package/scripts/verify-packed-consumer.mjs +84 -17
- package/scripts/verify-pier-agent.mts +6 -4
- package/src/benchmarks/_harness.test.mts +16 -1
- package/src/benchmarks/_harness.ts +9 -2
- package/src/benchmarks/terminal-bench.ts +2 -1
- package/src/corpus.test.mts +13 -0
- package/src/corpus.ts +4 -0
- package/src/profile-coordinates.ts +2 -2
- package/src/rollout-ledger/backfill-swe-arena.mts +5 -1
- package/src/rollout-ledger/settle-capture.mts +7 -1
- package/src/search-bench/profiles.ts +1 -1
- package/src/skill-sandbox-smoke.mts +2 -1
- package/src/swe-arena/gepa-seat.mts +1 -1
- package/src/swe-arena/ledger-orphans.test.mts +36 -34
- package/dist/benchmarks/cadbench.js.map +0 -1
- package/dist/benchmarks/cadgenbench.js.map +0 -1
- package/dist/benchmarks/types.js.map +0 -1
- package/dist/chunk-3U5TXJZS.js +0 -251
- package/dist/chunk-3U5TXJZS.js.map +0 -1
- package/dist/chunk-53UPUNBZ.js +0 -325
- package/dist/chunk-53UPUNBZ.js.map +0 -1
- package/dist/chunk-5H5XV76F.js +0 -240
- package/dist/chunk-5H5XV76F.js.map +0 -1
- package/dist/chunk-7GRVHU22.js +0 -208
- package/dist/chunk-7GRVHU22.js.map +0 -1
- package/dist/chunk-C7T7WEK2.js +0 -103
- package/dist/chunk-C7T7WEK2.js.map +0 -1
- package/dist/chunk-HWST3SED.js +0 -162
- package/dist/chunk-HWST3SED.js.map +0 -1
- package/dist/chunk-IA2FBTWC.js +0 -318
- package/dist/chunk-IA2FBTWC.js.map +0 -1
- package/dist/chunk-IFVINJ4B.js +0 -142
- package/dist/chunk-IFVINJ4B.js.map +0 -1
- package/dist/chunk-INNOYXCP.js +0 -387
- package/dist/chunk-INNOYXCP.js.map +0 -1
- package/dist/chunk-IZ5M6OAC.js +0 -169
- package/dist/chunk-IZ5M6OAC.js.map +0 -1
- package/dist/chunk-JTHWEDEW.js +0 -32
- package/dist/chunk-JTHWEDEW.js.map +0 -1
- package/dist/chunk-K3BQGZCT.js +0 -221
- package/dist/chunk-K3BQGZCT.js.map +0 -1
- package/dist/chunk-KP5KD6EN.js +0 -276
- package/dist/chunk-KP5KD6EN.js.map +0 -1
- package/dist/chunk-MQMRLGOG.js +0 -136
- package/dist/chunk-MQMRLGOG.js.map +0 -1
- package/dist/chunk-NQG5XDSB.js +0 -147
- package/dist/chunk-NQG5XDSB.js.map +0 -1
- package/dist/chunk-PA2ZKHJC.js +0 -230
- package/dist/chunk-PA2ZKHJC.js.map +0 -1
- package/dist/chunk-PB64GYIG.js +0 -118
- package/dist/chunk-PB64GYIG.js.map +0 -1
- package/dist/chunk-PUIRNYI7.js +0 -189
- package/dist/chunk-PUIRNYI7.js.map +0 -1
- package/dist/chunk-RCYQEFNX.js +0 -30
- package/dist/chunk-RCYQEFNX.js.map +0 -1
- package/dist/chunk-RH5F53JT.js +0 -182
- package/dist/chunk-RH5F53JT.js.map +0 -1
- package/dist/chunk-SEVJPLZC.js +0 -260
- package/dist/chunk-SEVJPLZC.js.map +0 -1
- package/dist/chunk-SFLA7OH3.js +0 -27
- package/dist/chunk-SFLA7OH3.js.map +0 -1
- package/dist/chunk-SHM6MRRF.js +0 -130
- package/dist/chunk-SHM6MRRF.js.map +0 -1
- package/dist/chunk-SHYIRB7I.js +0 -120
- package/dist/chunk-SHYIRB7I.js.map +0 -1
- package/dist/chunk-SVR2LKYI.js +0 -116
- package/dist/chunk-SVR2LKYI.js.map +0 -1
- package/dist/chunk-TBKU5XQI.js +0 -228
- package/dist/chunk-TBKU5XQI.js.map +0 -1
- package/dist/chunk-UPAMRDX4.js +0 -233
- package/dist/chunk-UPAMRDX4.js.map +0 -1
- package/dist/chunk-V7AEBY6U.js +0 -144
- package/dist/chunk-V7AEBY6U.js.map +0 -1
- package/dist/chunk-VQRS7VUC.js +0 -342
- package/dist/chunk-VQRS7VUC.js.map +0 -1
- package/dist/chunk-WSKWVEQB.js +0 -317
- package/dist/chunk-WSKWVEQB.js.map +0 -1
- package/dist/chunk-X3BTXCJ4.js +0 -262
- package/dist/chunk-X3BTXCJ4.js.map +0 -1
- package/dist/chunk-XKEFIFIC.js +0 -197
- package/dist/chunk-XKEFIFIC.js.map +0 -1
- package/dist/chunk-XYA4XSNU.js +0 -148
- package/dist/chunk-XYA4XSNU.js.map +0 -1
- package/dist/chunk-YSMEKBTD.js +0 -211
- package/dist/chunk-YSMEKBTD.js.map +0 -1
- package/dist/chunk-Z4TZ76N7.js +0 -170
- package/dist/chunk-Z4TZ76N7.js.map +0 -1
|
@@ -1,39 +1,246 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
//#region src/benchmarks/rag-shared.ts
|
|
3
|
+
const FINAL_ANSWER_SENTINEL = "FINAL ANSWER:";
|
|
4
|
+
const ragAnswerOutput = { parse(events) {
|
|
5
|
+
let text = "";
|
|
6
|
+
for (const ev of events) {
|
|
7
|
+
const d = ev?.data;
|
|
8
|
+
const t = d?.finalText ?? d?.text ?? d?.result;
|
|
9
|
+
if (typeof t === "string" && t.length > 0) text = t;
|
|
10
|
+
}
|
|
11
|
+
return text.trim();
|
|
12
|
+
} };
|
|
13
|
+
function parseFinalAnswer(artifact) {
|
|
14
|
+
const lines = artifact.split(/\r?\n/);
|
|
15
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
16
|
+
const line = lines[i] ?? "";
|
|
17
|
+
const idx = line.toUpperCase().indexOf(FINAL_ANSWER_SENTINEL);
|
|
18
|
+
if (idx !== -1) return line.slice(idx + 13).trim();
|
|
19
|
+
}
|
|
20
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
21
|
+
const trimmed = (lines[i] ?? "").trim();
|
|
22
|
+
if (trimmed.length > 0) return trimmed;
|
|
23
|
+
}
|
|
24
|
+
return "";
|
|
25
|
+
}
|
|
26
|
+
function parseCitations(artifact) {
|
|
27
|
+
const urls = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const match of artifact.matchAll(/https?:\/\/[^\s)<>"']+/g)) urls.add(match[0].replace(/[.,;]+$/, ""));
|
|
29
|
+
return [...urls];
|
|
30
|
+
}
|
|
31
|
+
function normalizeAnswer(input) {
|
|
32
|
+
return input.toLowerCase().replace(/(\d),(?=\d{3}\b)/g, "$1").replace(/[^\p{L}\p{N}\s.-]+/gu, " ").split(/\s+/).filter((token) => token.length > 0).filter((token) => ![
|
|
33
|
+
"a",
|
|
34
|
+
"an",
|
|
35
|
+
"the"
|
|
36
|
+
].includes(token)).join(" ").trim();
|
|
37
|
+
}
|
|
38
|
+
function tokens(input) {
|
|
39
|
+
const normalized = normalizeAnswer(input);
|
|
40
|
+
return normalized.length === 0 ? [] : normalized.split(/\s+/);
|
|
41
|
+
}
|
|
42
|
+
function tokenF1(candidate, gold) {
|
|
43
|
+
const candidateTokens = tokens(candidate);
|
|
44
|
+
const goldTokens = tokens(gold);
|
|
45
|
+
if (candidateTokens.length === 0 || goldTokens.length === 0) return candidateTokens.length === 0 && goldTokens.length === 0 ? 1 : 0;
|
|
46
|
+
const counts = /* @__PURE__ */ new Map();
|
|
47
|
+
for (const token of goldTokens) counts.set(token, (counts.get(token) ?? 0) + 1);
|
|
48
|
+
let common = 0;
|
|
49
|
+
for (const token of candidateTokens) {
|
|
50
|
+
const left = counts.get(token);
|
|
51
|
+
if (left !== void 0 && left > 0) {
|
|
52
|
+
common += 1;
|
|
53
|
+
counts.set(token, left - 1);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (common === 0) return 0;
|
|
57
|
+
const precision = common / candidateTokens.length;
|
|
58
|
+
const recall = common / goldTokens.length;
|
|
59
|
+
return 2 * precision * recall / (precision + recall);
|
|
60
|
+
}
|
|
61
|
+
function exactOrContains(candidate, gold) {
|
|
62
|
+
const normalizedCandidate = normalizeAnswer(candidate);
|
|
63
|
+
const normalizedGold = normalizeAnswer(gold);
|
|
64
|
+
if (normalizedGold.length === 0) return false;
|
|
65
|
+
if (normalizedCandidate === normalizedGold) return true;
|
|
66
|
+
const escaped = normalizedGold.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
67
|
+
return new RegExp(`(^|\\s)${escaped}(\\s|$)`).test(normalizedCandidate);
|
|
68
|
+
}
|
|
69
|
+
function numbers(input) {
|
|
70
|
+
return [...input.replace(/,/g, "").matchAll(/-?\d+(?:\.\d+)?/g)].map((match) => Number(match[0])).filter(Number.isFinite);
|
|
71
|
+
}
|
|
72
|
+
function numericMatch(candidate, gold, relativeTolerance) {
|
|
73
|
+
const got = numbers(candidate);
|
|
74
|
+
const want = numbers(gold);
|
|
75
|
+
if (got.length === 0 || want.length === 0) return false;
|
|
76
|
+
return want.some((expected) => got.some((actual) => {
|
|
77
|
+
const tolerance = Math.max(Math.abs(expected) * relativeTolerance, relativeTolerance);
|
|
78
|
+
return Math.abs(actual - expected) <= tolerance;
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
function scoreAnswerArtifact(artifact, golds, options = {}) {
|
|
82
|
+
const finalAnswer = parseFinalAnswer(artifact);
|
|
83
|
+
const threshold = options.threshold ?? .72;
|
|
84
|
+
const numericTolerance = options.numericTolerance ?? .01;
|
|
85
|
+
let best = {
|
|
86
|
+
resolved: false,
|
|
87
|
+
score: 0,
|
|
88
|
+
finalAnswer,
|
|
89
|
+
bestGold: null,
|
|
90
|
+
exact: false,
|
|
91
|
+
numeric: false,
|
|
92
|
+
f1: 0,
|
|
93
|
+
threshold
|
|
94
|
+
};
|
|
95
|
+
if (finalAnswer.length === 0 || golds.length === 0) return best;
|
|
96
|
+
for (const gold of golds) {
|
|
97
|
+
const exact = exactOrContains(finalAnswer, gold);
|
|
98
|
+
const numeric = numericMatch(finalAnswer, gold, numericTolerance);
|
|
99
|
+
const f1 = tokenF1(finalAnswer, gold);
|
|
100
|
+
const resolved = exact || numeric || f1 >= threshold;
|
|
101
|
+
const score = exact || numeric ? 1 : f1;
|
|
102
|
+
if (score > best.score || resolved && !best.resolved) best = {
|
|
103
|
+
resolved,
|
|
104
|
+
score,
|
|
105
|
+
finalAnswer,
|
|
106
|
+
bestGold: gold,
|
|
107
|
+
exact,
|
|
108
|
+
numeric,
|
|
109
|
+
f1,
|
|
110
|
+
threshold
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
return best;
|
|
114
|
+
}
|
|
115
|
+
function answerScoreToBenchScore(score, detail) {
|
|
116
|
+
return {
|
|
117
|
+
resolved: score.resolved,
|
|
118
|
+
score: score.score,
|
|
119
|
+
detail: JSON.stringify({
|
|
120
|
+
...detail,
|
|
121
|
+
finalAnswer: score.finalAnswer,
|
|
122
|
+
bestGold: score.bestGold,
|
|
123
|
+
exact: score.exact,
|
|
124
|
+
numeric: score.numeric,
|
|
125
|
+
f1: score.f1,
|
|
126
|
+
threshold: score.threshold
|
|
127
|
+
})
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
async function readJsonRows(path) {
|
|
131
|
+
const raw = (await readFile(path, "utf8")).trim();
|
|
132
|
+
if (raw.length === 0) return [];
|
|
133
|
+
if (raw.startsWith("[")) {
|
|
134
|
+
const parsed = JSON.parse(raw);
|
|
135
|
+
if (Array.isArray(parsed)) return parsed;
|
|
136
|
+
throw new Error(`${path} must contain a JSON array when it starts with [`);
|
|
137
|
+
}
|
|
138
|
+
if (raw.startsWith("{")) try {
|
|
139
|
+
const parsed = JSON.parse(raw);
|
|
140
|
+
if (isObject(parsed)) {
|
|
141
|
+
for (const key of [
|
|
142
|
+
"rows",
|
|
143
|
+
"data",
|
|
144
|
+
"examples",
|
|
145
|
+
"items"
|
|
146
|
+
]) {
|
|
147
|
+
const value = parsed[key];
|
|
148
|
+
if (Array.isArray(value)) return value;
|
|
149
|
+
}
|
|
150
|
+
return [parsed];
|
|
151
|
+
}
|
|
152
|
+
throw new Error(`${path} must contain a JSON object, JSON array, JSONL rows, or an object with rows/data/examples/items`);
|
|
153
|
+
} catch (err) {
|
|
154
|
+
if (!raw.includes("\n")) throw err;
|
|
155
|
+
}
|
|
156
|
+
return raw.split(/\r?\n/).map((line) => line.trim()).filter((line) => line.length > 0).map((line) => JSON.parse(line));
|
|
157
|
+
}
|
|
158
|
+
function selectTasks(tasks, opts, label) {
|
|
159
|
+
let selected = tasks;
|
|
160
|
+
if (opts.split) selected = selected.filter((task) => task.split === opts.split);
|
|
161
|
+
if (opts.ids) {
|
|
162
|
+
const ids = new Set(opts.ids);
|
|
163
|
+
selected = selected.filter((task) => ids.has(task.id));
|
|
164
|
+
} else if (opts.limit !== void 0) selected = selected.slice(0, opts.limit);
|
|
165
|
+
if (selected.length === 0) throw new Error(`${label}: no tasks matched ${JSON.stringify(opts)}`);
|
|
166
|
+
return selected;
|
|
167
|
+
}
|
|
168
|
+
function stringFrom(value) {
|
|
169
|
+
return typeof value === "string" && value.trim().length > 0 ? value.trim() : void 0;
|
|
170
|
+
}
|
|
171
|
+
function stringArrayFrom(value) {
|
|
172
|
+
if (typeof value === "string" && value.trim().length > 0) return [value.trim()];
|
|
173
|
+
if (!Array.isArray(value)) return [];
|
|
174
|
+
return value.flatMap((entry) => {
|
|
175
|
+
if (typeof entry === "string" && entry.trim().length > 0) return [entry.trim()];
|
|
176
|
+
if (isObject(entry)) {
|
|
177
|
+
const text = stringFrom(entry.answer) ?? stringFrom(entry.value) ?? stringFrom(entry.text);
|
|
178
|
+
return text ? [text] : [];
|
|
179
|
+
}
|
|
180
|
+
return [];
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
function firstString(row, keys) {
|
|
184
|
+
for (const key of keys) {
|
|
185
|
+
const value = stringFrom(row[key]);
|
|
186
|
+
if (value) return value;
|
|
187
|
+
}
|
|
188
|
+
return "";
|
|
189
|
+
}
|
|
190
|
+
function allStrings(row, keys) {
|
|
191
|
+
const out = [];
|
|
192
|
+
for (const key of keys) out.push(...stringArrayFrom(row[key]));
|
|
193
|
+
return [...new Set(out)];
|
|
194
|
+
}
|
|
195
|
+
function contextsFrom(value) {
|
|
196
|
+
if (typeof value === "string" && value.trim().length > 0) return [{
|
|
197
|
+
id: "ctx-1",
|
|
198
|
+
text: value.trim()
|
|
199
|
+
}];
|
|
200
|
+
if (!Array.isArray(value)) return [];
|
|
201
|
+
return value.flatMap((entry, index) => {
|
|
202
|
+
if (typeof entry === "string" && entry.trim().length > 0) return [{
|
|
203
|
+
id: `ctx-${index + 1}`,
|
|
204
|
+
text: entry.trim()
|
|
205
|
+
}];
|
|
206
|
+
if (Array.isArray(entry)) {
|
|
207
|
+
const [first, second] = entry;
|
|
208
|
+
if (typeof first === "string" && typeof second === "string") return [{
|
|
209
|
+
id: first,
|
|
210
|
+
text: second.trim()
|
|
211
|
+
}];
|
|
212
|
+
return entry.flatMap((nested, nestedIndex) => contextsFrom([nested]).map((ctx) => ({
|
|
213
|
+
...ctx,
|
|
214
|
+
id: ctx.id.startsWith("ctx-") ? `ctx-${index + 1}-${nestedIndex + 1}` : ctx.id
|
|
215
|
+
})));
|
|
216
|
+
}
|
|
217
|
+
if (!isObject(entry)) return [];
|
|
218
|
+
const text = stringFrom(entry.text) ?? stringFrom(entry.context) ?? stringFrom(entry.content) ?? stringFrom(entry.passage) ?? stringFrom(entry.document) ?? stringFrom(entry.page_content) ?? stringFrom(entry.chunk);
|
|
219
|
+
if (!text) return [];
|
|
220
|
+
const id = stringFrom(entry.id) ?? stringFrom(entry.docid) ?? stringFrom(entry.doc_id) ?? stringFrom(entry.document_id) ?? `ctx-${index + 1}`;
|
|
221
|
+
const relevantRaw = entry.relevant ?? entry.is_relevant ?? entry.label ?? entry.relevance;
|
|
222
|
+
const relevant = typeof relevantRaw === "boolean" ? relevantRaw : typeof relevantRaw === "number" ? relevantRaw > 0 : void 0;
|
|
223
|
+
return [{
|
|
224
|
+
id,
|
|
225
|
+
text,
|
|
226
|
+
...stringFrom(entry.title) ? { title: stringFrom(entry.title) } : {},
|
|
227
|
+
...stringFrom(entry.source) ?? stringFrom(entry.url) ? { source: stringFrom(entry.source) ?? stringFrom(entry.url) } : {},
|
|
228
|
+
...relevant !== void 0 ? { relevant } : {}
|
|
229
|
+
}];
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
function contextBlock(contexts) {
|
|
233
|
+
if (contexts.length === 0) return "";
|
|
234
|
+
return contexts.map((ctx, index) => [
|
|
235
|
+
`[${index + 1}] ${ctx.title ?? ctx.id}`,
|
|
236
|
+
ctx.source ? `Source: ${ctx.source}` : void 0,
|
|
237
|
+
ctx.text
|
|
238
|
+
].filter(Boolean).join("\n")).join("\n\n");
|
|
239
|
+
}
|
|
240
|
+
function isObject(value) {
|
|
241
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
242
|
+
}
|
|
243
|
+
//#endregion
|
|
244
|
+
export { FINAL_ANSWER_SENTINEL, allStrings, answerScoreToBenchScore, contextBlock, contextsFrom, firstString, isObject, normalizeAnswer, parseCitations, parseFinalAnswer, ragAnswerOutput, readJsonRows, scoreAnswerArtifact, selectTasks, stringArrayFrom, stringFrom, tokenF1 };
|
|
245
|
+
|
|
39
246
|
//# sourceMappingURL=rag-shared.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
1
|
+
{"version":3,"file":"rag-shared.js","names":[],"sources":["../../src/benchmarks/rag-shared.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\nimport type { OutputAdapter } from '@tangle-network/agent-runtime/loops'\nimport type { BenchScore, BenchTask, LoadOptions } from './types'\n\nexport const FINAL_ANSWER_SENTINEL = 'FINAL ANSWER:'\n\nexport interface RagContext {\n id: string\n text: string\n title?: string\n source?: string\n relevant?: boolean\n}\n\nexport interface RagAnswerScore {\n resolved: boolean\n score: number\n finalAnswer: string\n bestGold: string | null\n exact: boolean\n numeric: boolean\n f1: number\n threshold: number\n}\n\nexport const ragAnswerOutput: OutputAdapter<string> = {\n parse(events) {\n let text = ''\n for (const ev of events) {\n const d = (ev as { data?: Record<string, unknown> })?.data\n const t = d?.finalText ?? d?.text ?? d?.result\n if (typeof t === 'string' && t.length > 0) text = t\n }\n return text.trim()\n },\n}\n\nexport function parseFinalAnswer(artifact: string): string {\n const lines = artifact.split(/\\r?\\n/)\n for (let i = lines.length - 1; i >= 0; i -= 1) {\n const line = lines[i] ?? ''\n const idx = line.toUpperCase().indexOf(FINAL_ANSWER_SENTINEL)\n if (idx !== -1) return line.slice(idx + FINAL_ANSWER_SENTINEL.length).trim()\n }\n for (let i = lines.length - 1; i >= 0; i -= 1) {\n const trimmed = (lines[i] ?? '').trim()\n if (trimmed.length > 0) return trimmed\n }\n return ''\n}\n\nexport function parseCitations(artifact: string): string[] {\n const urls = new Set<string>()\n for (const match of artifact.matchAll(/https?:\\/\\/[^\\s)<>\"']+/g)) {\n urls.add(match[0].replace(/[.,;]+$/, ''))\n }\n return [...urls]\n}\n\nexport function normalizeAnswer(input: string): string {\n return input\n .toLowerCase()\n .replace(/(\\d),(?=\\d{3}\\b)/g, '$1')\n .replace(/[^\\p{L}\\p{N}\\s.-]+/gu, ' ')\n .split(/\\s+/)\n .filter((token) => token.length > 0)\n .filter((token) => !['a', 'an', 'the'].includes(token))\n .join(' ')\n .trim()\n}\n\nfunction tokens(input: string): string[] {\n const normalized = normalizeAnswer(input)\n return normalized.length === 0 ? [] : normalized.split(/\\s+/)\n}\n\nexport function tokenF1(candidate: string, gold: string): number {\n const candidateTokens = tokens(candidate)\n const goldTokens = tokens(gold)\n if (candidateTokens.length === 0 || goldTokens.length === 0) {\n return candidateTokens.length === 0 && goldTokens.length === 0 ? 1 : 0\n }\n const counts = new Map<string, number>()\n for (const token of goldTokens) counts.set(token, (counts.get(token) ?? 0) + 1)\n let common = 0\n for (const token of candidateTokens) {\n const left = counts.get(token)\n if (left !== undefined && left > 0) {\n common += 1\n counts.set(token, left - 1)\n }\n }\n if (common === 0) return 0\n const precision = common / candidateTokens.length\n const recall = common / goldTokens.length\n return (2 * precision * recall) / (precision + recall)\n}\n\nfunction exactOrContains(candidate: string, gold: string): boolean {\n const normalizedCandidate = normalizeAnswer(candidate)\n const normalizedGold = normalizeAnswer(gold)\n if (normalizedGold.length === 0) return false\n if (normalizedCandidate === normalizedGold) return true\n const escaped = normalizedGold.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n return new RegExp(`(^|\\\\s)${escaped}(\\\\s|$)`).test(normalizedCandidate)\n}\n\nfunction numbers(input: string): number[] {\n return [...input.replace(/,/g, '').matchAll(/-?\\d+(?:\\.\\d+)?/g)]\n .map((match) => Number(match[0]))\n .filter(Number.isFinite)\n}\n\nfunction numericMatch(candidate: string, gold: string, relativeTolerance: number): boolean {\n const got = numbers(candidate)\n const want = numbers(gold)\n if (got.length === 0 || want.length === 0) return false\n return want.some((expected) =>\n got.some((actual) => {\n const tolerance = Math.max(Math.abs(expected) * relativeTolerance, relativeTolerance)\n return Math.abs(actual - expected) <= tolerance\n }),\n )\n}\n\nexport function scoreAnswerArtifact(\n artifact: string,\n golds: readonly string[],\n options: { threshold?: number; numericTolerance?: number } = {},\n): RagAnswerScore {\n const finalAnswer = parseFinalAnswer(artifact)\n const threshold = options.threshold ?? 0.72\n const numericTolerance = options.numericTolerance ?? 0.01\n let best: RagAnswerScore = {\n resolved: false,\n score: 0,\n finalAnswer,\n bestGold: null,\n exact: false,\n numeric: false,\n f1: 0,\n threshold,\n }\n if (finalAnswer.length === 0 || golds.length === 0) return best\n\n for (const gold of golds) {\n const exact = exactOrContains(finalAnswer, gold)\n const numeric = numericMatch(finalAnswer, gold, numericTolerance)\n const f1 = tokenF1(finalAnswer, gold)\n const resolved = exact || numeric || f1 >= threshold\n const score = exact || numeric ? 1 : f1\n if (score > best.score || (resolved && !best.resolved)) {\n best = { resolved, score, finalAnswer, bestGold: gold, exact, numeric, f1, threshold }\n }\n }\n return best\n}\n\nexport function answerScoreToBenchScore(\n score: RagAnswerScore,\n detail: Record<string, unknown>,\n): BenchScore {\n return {\n resolved: score.resolved,\n score: score.score,\n detail: JSON.stringify({\n ...detail,\n finalAnswer: score.finalAnswer,\n bestGold: score.bestGold,\n exact: score.exact,\n numeric: score.numeric,\n f1: score.f1,\n threshold: score.threshold,\n }),\n }\n}\n\nexport async function readJsonRows(path: string): Promise<unknown[]> {\n const raw = (await readFile(path, 'utf8')).trim()\n if (raw.length === 0) return []\n if (raw.startsWith('[')) {\n const parsed = JSON.parse(raw) as unknown\n if (Array.isArray(parsed)) return parsed\n throw new Error(`${path} must contain a JSON array when it starts with [`)\n }\n if (raw.startsWith('{')) {\n try {\n const parsed = JSON.parse(raw) as unknown\n if (isObject(parsed)) {\n for (const key of ['rows', 'data', 'examples', 'items']) {\n const value = parsed[key]\n if (Array.isArray(value)) return value\n }\n return [parsed]\n }\n throw new Error(`${path} must contain a JSON object, JSON array, JSONL rows, or an object with rows/data/examples/items`)\n } catch (err) {\n if (!raw.includes('\\n')) throw err\n }\n }\n return raw\n .split(/\\r?\\n/)\n .map((line) => line.trim())\n .filter((line) => line.length > 0)\n .map((line) => JSON.parse(line) as unknown)\n}\n\nexport function selectTasks(tasks: BenchTask[], opts: LoadOptions, label: string): BenchTask[] {\n let selected = tasks\n if (opts.split) selected = selected.filter((task) => task.split === opts.split)\n if (opts.ids) {\n const ids = new Set(opts.ids)\n selected = selected.filter((task) => ids.has(task.id))\n } else if (opts.limit !== undefined) {\n selected = selected.slice(0, opts.limit)\n }\n if (selected.length === 0) throw new Error(`${label}: no tasks matched ${JSON.stringify(opts)}`)\n return selected\n}\n\nexport function stringFrom(value: unknown): string | undefined {\n return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined\n}\n\nexport function stringArrayFrom(value: unknown): string[] {\n if (typeof value === 'string' && value.trim().length > 0) return [value.trim()]\n if (!Array.isArray(value)) return []\n return value.flatMap((entry) => {\n if (typeof entry === 'string' && entry.trim().length > 0) return [entry.trim()]\n if (isObject(entry)) {\n const text = stringFrom(entry.answer) ?? stringFrom(entry.value) ?? stringFrom(entry.text)\n return text ? [text] : []\n }\n return []\n })\n}\n\nexport function firstString(row: Record<string, unknown>, keys: readonly string[]): string {\n for (const key of keys) {\n const value = stringFrom(row[key])\n if (value) return value\n }\n return ''\n}\n\nexport function allStrings(row: Record<string, unknown>, keys: readonly string[]): string[] {\n const out: string[] = []\n for (const key of keys) out.push(...stringArrayFrom(row[key]))\n return [...new Set(out)]\n}\n\nexport function contextsFrom(value: unknown): RagContext[] {\n if (typeof value === 'string' && value.trim().length > 0) {\n return [{ id: 'ctx-1', text: value.trim() }]\n }\n if (!Array.isArray(value)) return []\n return value.flatMap((entry, index): RagContext[] => {\n if (typeof entry === 'string' && entry.trim().length > 0) {\n return [{ id: `ctx-${index + 1}`, text: entry.trim() }]\n }\n if (Array.isArray(entry)) {\n const [first, second] = entry\n if (typeof first === 'string' && typeof second === 'string') {\n return [{ id: first, text: second.trim() }]\n }\n return entry.flatMap((nested, nestedIndex) =>\n contextsFrom([nested]).map((ctx) => ({\n ...ctx,\n id: ctx.id.startsWith('ctx-') ? `ctx-${index + 1}-${nestedIndex + 1}` : ctx.id,\n })),\n )\n }\n if (!isObject(entry)) return []\n const text =\n stringFrom(entry.text) ??\n stringFrom(entry.context) ??\n stringFrom(entry.content) ??\n stringFrom(entry.passage) ??\n stringFrom(entry.document) ??\n stringFrom(entry.page_content) ??\n stringFrom(entry.chunk)\n if (!text) return []\n const id =\n stringFrom(entry.id) ??\n stringFrom(entry.docid) ??\n stringFrom(entry.doc_id) ??\n stringFrom(entry.document_id) ??\n `ctx-${index + 1}`\n const relevantRaw = entry.relevant ?? entry.is_relevant ?? entry.label ?? entry.relevance\n const relevant =\n typeof relevantRaw === 'boolean'\n ? relevantRaw\n : typeof relevantRaw === 'number'\n ? relevantRaw > 0\n : undefined\n return [\n {\n id,\n text,\n ...(stringFrom(entry.title) ? { title: stringFrom(entry.title) } : {}),\n ...(stringFrom(entry.source) ?? stringFrom(entry.url)\n ? { source: stringFrom(entry.source) ?? stringFrom(entry.url) }\n : {}),\n ...(relevant !== undefined ? { relevant } : {}),\n },\n ]\n })\n}\n\nexport function contextBlock(contexts: readonly RagContext[]): string {\n if (contexts.length === 0) return ''\n return contexts\n .map((ctx, index) =>\n [\n `[${index + 1}] ${ctx.title ?? ctx.id}`,\n ctx.source ? `Source: ${ctx.source}` : undefined,\n ctx.text,\n ]\n .filter(Boolean)\n .join('\\n'),\n )\n .join('\\n\\n')\n}\n\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value)\n}\n"],"mappings":"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"}
|
|
@@ -1,16 +1,6 @@
|
|
|
1
|
-
import { BenchmarkAdapter } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* RAGBench-compatible adapter.
|
|
6
|
-
*
|
|
7
|
-
* Live mode expects a local JSON/JSONL export from rungalileo/ragbench or a
|
|
8
|
-
* compatible table. Rows must carry a query and at least one reference answer.
|
|
9
|
-
* Contexts, TRACe labels, and source metadata are preserved in task metadata
|
|
10
|
-
* for diagnostics; the deterministic judge scores the worker's final answer
|
|
11
|
-
* against the reference answer(s).
|
|
12
|
-
*/
|
|
13
|
-
|
|
1
|
+
import { BenchmarkAdapter } from "./types.js";
|
|
2
|
+
//#region src/benchmarks/ragbench.d.ts
|
|
14
3
|
declare function createRagBenchAdapter(): BenchmarkAdapter;
|
|
15
|
-
|
|
4
|
+
//#endregion
|
|
16
5
|
export { createRagBenchAdapter };
|
|
6
|
+
//# sourceMappingURL=ragbench.d.ts.map
|
|
@@ -1,9 +1,128 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
} from "
|
|
4
|
-
import "
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { benchRoot } from "./_harness.js";
|
|
2
|
+
import { FINAL_ANSWER_SENTINEL, allStrings, answerScoreToBenchScore, contextBlock, contextsFrom, firstString, isObject, ragAnswerOutput, readJsonRows, scoreAnswerArtifact, selectTasks, stringFrom } from "./rag-shared.js";
|
|
3
|
+
import { readFile } from "node:fs/promises";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
//#region src/benchmarks/ragbench.ts
|
|
6
|
+
/**
|
|
7
|
+
* RAGBench-compatible adapter.
|
|
8
|
+
*
|
|
9
|
+
* Live mode expects a local JSON/JSONL export from rungalileo/ragbench or a
|
|
10
|
+
* compatible table. Rows must carry a query and at least one reference answer.
|
|
11
|
+
* Contexts, TRACe labels, and source metadata are preserved in task metadata
|
|
12
|
+
* for diagnostics; the deterministic judge scores the worker's final answer
|
|
13
|
+
* against the reference answer(s).
|
|
14
|
+
*/
|
|
15
|
+
const FIXTURES = join(benchRoot, "fixtures", "ragbench.json");
|
|
16
|
+
const dataFile = () => process.env.RAGBENCH_DATA_FILE;
|
|
17
|
+
function rowToTask(raw, index) {
|
|
18
|
+
if (!isObject(raw)) throw new Error(`RAGBench row ${index} must be an object`);
|
|
19
|
+
const query = firstString(raw, [
|
|
20
|
+
"question",
|
|
21
|
+
"query",
|
|
22
|
+
"user_input",
|
|
23
|
+
"prompt"
|
|
24
|
+
]);
|
|
25
|
+
const goldAnswers = allStrings(raw, [
|
|
26
|
+
"response",
|
|
27
|
+
"responses",
|
|
28
|
+
"model_response",
|
|
29
|
+
"generated_response",
|
|
30
|
+
"reference",
|
|
31
|
+
"references",
|
|
32
|
+
"reference_answer",
|
|
33
|
+
"reference_answers",
|
|
34
|
+
"answer",
|
|
35
|
+
"answers",
|
|
36
|
+
"gold",
|
|
37
|
+
"gold_answer",
|
|
38
|
+
"ground_truth",
|
|
39
|
+
"expected_answer"
|
|
40
|
+
]);
|
|
41
|
+
if (!query) throw new Error(`RAGBench row ${index} missing question/query`);
|
|
42
|
+
if (goldAnswers.length === 0) throw new Error(`RAGBench row ${index} missing reference answer`);
|
|
43
|
+
const contexts = contextsFrom(raw.contexts).length > 0 ? contextsFrom(raw.contexts) : contextsFrom(raw.retrieved_contexts).length > 0 ? contextsFrom(raw.retrieved_contexts) : contextsFrom(raw.documents);
|
|
44
|
+
const traceLabels = {};
|
|
45
|
+
for (const key of [
|
|
46
|
+
"adherence",
|
|
47
|
+
"completeness",
|
|
48
|
+
"relevance",
|
|
49
|
+
"utilization",
|
|
50
|
+
"all_relevant_sentence_keys",
|
|
51
|
+
"all_utilized_sentence_keys"
|
|
52
|
+
]) if (raw[key] !== void 0) traceLabels[key] = raw[key];
|
|
53
|
+
const dataset = stringFrom(raw.dataset) ?? stringFrom(raw.source_dataset);
|
|
54
|
+
const id = stringFrom(raw.id) ?? stringFrom(raw.example_id) ?? `ragbench-${index}`;
|
|
55
|
+
const meta = {
|
|
56
|
+
benchmark: "ragbench",
|
|
57
|
+
query,
|
|
58
|
+
goldAnswers,
|
|
59
|
+
contexts,
|
|
60
|
+
...dataset ? { dataset } : {},
|
|
61
|
+
traceLabels
|
|
62
|
+
};
|
|
63
|
+
return {
|
|
64
|
+
id,
|
|
65
|
+
split: stringFrom(raw.split) ?? dataset ?? "ragbench",
|
|
66
|
+
prompt: [
|
|
67
|
+
"Answer this RAGBench question using the supplied retrieved context.",
|
|
68
|
+
"End with a single final line: `FINAL ANSWER: <answer>`.",
|
|
69
|
+
"",
|
|
70
|
+
`Question: ${query}`,
|
|
71
|
+
contexts.length > 0 ? `\nRetrieved context:\n${contextBlock(contexts)}` : void 0
|
|
72
|
+
].filter(Boolean).join("\n"),
|
|
73
|
+
metadata: meta
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
function readMeta(task) {
|
|
77
|
+
const md = task.metadata;
|
|
78
|
+
if (!md || !Array.isArray(md.goldAnswers)) throw new Error(`RAGBench task ${task.id} missing metadata — loadTasks did not populate it`);
|
|
79
|
+
return md;
|
|
80
|
+
}
|
|
81
|
+
async function loadRows(path) {
|
|
82
|
+
const rows = await readJsonRows(path);
|
|
83
|
+
if (rows.length === 0) throw new Error(`RAGBench: no rows in ${path}`);
|
|
84
|
+
return rows;
|
|
85
|
+
}
|
|
86
|
+
async function loadFixtures(opts) {
|
|
87
|
+
const rows = JSON.parse(await readFile(FIXTURES, "utf8"));
|
|
88
|
+
console.warn(`[ragbench] RAGBENCH_FIXTURES=1 — loading ${rows.length} adapter fixtures`);
|
|
89
|
+
return selectTasks(rows.map(rowToTask), opts, "RAGBench");
|
|
90
|
+
}
|
|
91
|
+
function createRagBenchAdapter() {
|
|
92
|
+
const fixturesMode = process.env.RAGBENCH_FIXTURES === "1";
|
|
93
|
+
return {
|
|
94
|
+
name: "ragbench",
|
|
95
|
+
output: ragAnswerOutput,
|
|
96
|
+
async preflight() {
|
|
97
|
+
if (fixturesMode) {
|
|
98
|
+
await readFile(FIXTURES, "utf8");
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const path = dataFile();
|
|
102
|
+
if (!path) throw new Error("RAGBENCH_DATA_FILE is required. Fix: export rungalileo/ragbench rows to JSONL and set RAGBENCH_DATA_FILE=/path/to/ragbench.jsonl, or set RAGBENCH_FIXTURES=1 for adapter plumbing.");
|
|
103
|
+
await loadRows(path);
|
|
104
|
+
},
|
|
105
|
+
async loadTasks(opts = {}) {
|
|
106
|
+
if (fixturesMode) return loadFixtures(opts);
|
|
107
|
+
const path = dataFile();
|
|
108
|
+
if (!path) throw new Error("RAGBENCH_DATA_FILE is required to load RAGBench tasks");
|
|
109
|
+
return selectTasks((await loadRows(path)).map(rowToTask), opts, "RAGBench");
|
|
110
|
+
},
|
|
111
|
+
async goldArtifact(task) {
|
|
112
|
+
return `${FINAL_ANSWER_SENTINEL} ${readMeta(task).goldAnswers[0] ?? ""}`;
|
|
113
|
+
},
|
|
114
|
+
async judge(task, artifact) {
|
|
115
|
+
const meta = readMeta(task);
|
|
116
|
+
return answerScoreToBenchScore(scoreAnswerArtifact(artifact, meta.goldAnswers), {
|
|
117
|
+
benchmark: meta.benchmark,
|
|
118
|
+
dataset: meta.dataset ?? null,
|
|
119
|
+
traceLabels: meta.traceLabels,
|
|
120
|
+
contextCount: meta.contexts.length
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
//#endregion
|
|
126
|
+
export { createRagBenchAdapter };
|
|
127
|
+
|
|
9
128
|
//# sourceMappingURL=ragbench.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"
|
|
1
|
+
{"version":3,"file":"ragbench.js","names":[],"sources":["../../src/benchmarks/ragbench.ts"],"sourcesContent":["/**\n * RAGBench-compatible adapter.\n *\n * Live mode expects a local JSON/JSONL export from rungalileo/ragbench or a\n * compatible table. Rows must carry a query and at least one reference answer.\n * Contexts, TRACe labels, and source metadata are preserved in task metadata\n * for diagnostics; the deterministic judge scores the worker's final answer\n * against the reference answer(s).\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', 'ragbench.json')\n\ninterface RagBenchMeta {\n benchmark: 'ragbench'\n query: string\n goldAnswers: string[]\n contexts: RagContext[]\n dataset?: string\n traceLabels: Record<string, unknown>\n}\n\nconst dataFile = (): string | undefined => process.env.RAGBENCH_DATA_FILE\n\nfunction rowToTask(raw: unknown, index: number): BenchTask {\n if (!isObject(raw)) throw new Error(`RAGBench row ${index} must be an object`)\n const query = firstString(raw, ['question', 'query', 'user_input', 'prompt'])\n const goldAnswers = allStrings(raw, [\n 'response',\n 'responses',\n 'model_response',\n 'generated_response',\n 'reference',\n 'references',\n 'reference_answer',\n 'reference_answers',\n 'answer',\n 'answers',\n 'gold',\n 'gold_answer',\n 'ground_truth',\n 'expected_answer',\n ])\n if (!query) throw new Error(`RAGBench row ${index} missing question/query`)\n if (goldAnswers.length === 0) throw new Error(`RAGBench row ${index} missing reference answer`)\n const contexts =\n contextsFrom(raw.contexts).length > 0\n ? contextsFrom(raw.contexts)\n : contextsFrom(raw.retrieved_contexts).length > 0\n ? contextsFrom(raw.retrieved_contexts)\n : contextsFrom(raw.documents)\n const traceLabels: Record<string, unknown> = {}\n for (const key of [\n 'adherence',\n 'completeness',\n 'relevance',\n 'utilization',\n 'all_relevant_sentence_keys',\n 'all_utilized_sentence_keys',\n ]) {\n if (raw[key] !== undefined) traceLabels[key] = raw[key]\n }\n const dataset = stringFrom(raw.dataset) ?? stringFrom(raw.source_dataset)\n const id = stringFrom(raw.id) ?? stringFrom(raw.example_id) ?? `ragbench-${index}`\n const meta: RagBenchMeta = {\n benchmark: 'ragbench',\n query,\n goldAnswers,\n contexts,\n ...(dataset ? { dataset } : {}),\n traceLabels,\n }\n return {\n id,\n split: stringFrom(raw.split) ?? dataset ?? 'ragbench',\n prompt: [\n 'Answer this RAGBench question using the supplied retrieved context.',\n 'End with a single final line: `FINAL ANSWER: <answer>`.',\n '',\n `Question: ${query}`,\n contexts.length > 0 ? `\\nRetrieved 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): RagBenchMeta {\n const md = task.metadata\n if (!md || !Array.isArray(md.goldAnswers)) {\n throw new Error(`RAGBench task ${task.id} missing metadata — loadTasks did not populate it`)\n }\n return md as unknown as RagBenchMeta\n}\n\nasync function loadRows(path: string): Promise<unknown[]> {\n const rows = await readJsonRows(path)\n if (rows.length === 0) throw new Error(`RAGBench: 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(`[ragbench] RAGBENCH_FIXTURES=1 — loading ${rows.length} adapter fixtures`)\n return selectTasks(rows.map(rowToTask), opts, 'RAGBench')\n}\n\nexport function createRagBenchAdapter(): BenchmarkAdapter {\n const fixturesMode = process.env.RAGBENCH_FIXTURES === '1'\n\n return {\n name: 'ragbench',\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 'RAGBENCH_DATA_FILE is required. Fix: export rungalileo/ragbench rows to JSONL and set RAGBENCH_DATA_FILE=/path/to/ragbench.jsonl, or set RAGBENCH_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('RAGBENCH_DATA_FILE is required to load RAGBench tasks')\n return selectTasks((await loadRows(path)).map(rowToTask), opts, 'RAGBench')\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 dataset: meta.dataset ?? null,\n traceLabels: meta.traceLabels,\n contextCount: meta.contexts.length,\n })\n },\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,33 +1,5 @@
|
|
|
1
|
-
import { BenchmarkAdapter } from
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* SimpleQA adapter (OpenAI simple-evals; short-form factual QA). Worker artifact
|
|
6
|
-
* = a single free-text final answer string (optionally preceded by a CITATIONS:
|
|
7
|
-
* block). Each item ships a short gold `answer` plus metadata (topic,
|
|
8
|
-
* answer_type, source urls).
|
|
9
|
-
*
|
|
10
|
-
* Judge is the official SimpleQA grader — an LLM classifier that maps
|
|
11
|
-
* (question, gold target, predicted answer) to exactly one of:
|
|
12
|
-
* A = CORRECT — fully contains the gold, no contradiction
|
|
13
|
-
* B = INCORRECT — contradicts / contains a different factual value
|
|
14
|
-
* C = NOT_ATTEMPTED — hedged, non-committal, or no value given
|
|
15
|
-
* resolved = (grade == CORRECT). score = 1 for CORRECT else 0. The grade letter
|
|
16
|
-
* (with its label) rides in `detail`; NOT_ATTEMPTED is surfaced distinctly from
|
|
17
|
-
* INCORRECT so the scorecard can separate abstention from error.
|
|
18
|
-
*
|
|
19
|
-
* There is no deterministic tier: SimpleQA's rubric (containment + abstention)
|
|
20
|
-
* is the grader's job by design, so judge() always calls the pinned grader model
|
|
21
|
-
* (temperature 0) and fails loud on unparseable grader output. The final-answer
|
|
22
|
-
* extraction IS deterministic (FINAL ANSWER: sentinel, fail-closed to '').
|
|
23
|
-
*
|
|
24
|
-
* Requires for a live run: the bench `.venv` with `datasets`/`requests` not
|
|
25
|
-
* needed — the test set is a single public CSV fetched over HTTP — plus a
|
|
26
|
-
* grader key (TANGLE_API_KEY). For offline/CI verification set
|
|
27
|
-
* SIMPLEQA_FIXTURES=1 to load the committed fixtures
|
|
28
|
-
* (bench/fixtures/simpleqa.json) — no network.
|
|
29
|
-
*/
|
|
30
|
-
|
|
1
|
+
import { BenchmarkAdapter } from "./types.js";
|
|
2
|
+
//#region src/benchmarks/simpleqa.d.ts
|
|
31
3
|
/**
|
|
32
4
|
* Typed seam for the research worker. The benchmark adapter scores a plain
|
|
33
5
|
* `string` artifact (the BenchmarkAdapter contract); the loop worker decodes its
|
|
@@ -35,20 +7,20 @@ import '@tangle-network/agent-runtime/loops';
|
|
|
35
7
|
* optional `CITATIONS:` block) into that string before judging.
|
|
36
8
|
*/
|
|
37
9
|
interface ResearchTask {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
10
|
+
id: string;
|
|
11
|
+
question: string;
|
|
12
|
+
/** Gold short answer — the grader's target. */
|
|
13
|
+
gold: string;
|
|
14
|
+
/** Source URLs cited by the dataset for this item — SOFT provenance signal, never a hard gate. */
|
|
15
|
+
goldSources: string[];
|
|
16
|
+
/** SimpleQA topic, e.g. 'Politics' — slices the scorecard by domain. */
|
|
17
|
+
topic: string;
|
|
18
|
+
/** SimpleQA answer_type, e.g. 'Person' | 'Date' | 'Number' | 'Place'. */
|
|
19
|
+
answerType: string;
|
|
48
20
|
}
|
|
49
21
|
interface ResearchAnswer {
|
|
50
|
-
|
|
51
|
-
|
|
22
|
+
finalAnswer: string;
|
|
23
|
+
citations: string[];
|
|
52
24
|
}
|
|
53
25
|
/**
|
|
54
26
|
* Parse the worker artifact into the final answer string.
|
|
@@ -60,5 +32,6 @@ declare function parseFinalAnswer(artifact: string): string;
|
|
|
60
32
|
/** Extract every bare URL in the artifact (CITATIONS: block + inline). SOFT provenance signal. */
|
|
61
33
|
declare function parseCitations(artifact: string): string[];
|
|
62
34
|
declare function createSimpleQaAdapter(): BenchmarkAdapter;
|
|
63
|
-
|
|
64
|
-
export {
|
|
35
|
+
//#endregion
|
|
36
|
+
export { ResearchAnswer, ResearchTask, createSimpleQaAdapter, parseCitations, parseFinalAnswer };
|
|
37
|
+
//# sourceMappingURL=simpleqa.d.ts.map
|