@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 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/benchmarks/frames.ts"],"sourcesContent":["/**\n * FRAMES adapter (google/frames-benchmark). Worker artifact = a single free-text\n * final answer string (optionally preceded by a citations block). FRAMES ships,\n * per item, a short gold `Answer` PLUS gold `wiki_links` (the Wikipedia URLs\n * needed to answer) — the gold-citation column is what lets the loop's critic\n * check citation coverage deterministically.\n *\n * Judge is two-tier, deterministic-first:\n * Tier 1 — normalized exact / token-boundary containment match (no model tokens).\n * Tier 2 — a constrained binary equivalence gate via a pinned LLM (JUDGE_MODEL,\n * temperature 0), fired ONLY when Tier 1 misses, to absorb the\n * paraphrase/alias equivalence FRAMES intends to allow.\n *\n * score is binary (resolved ? 1 : 0) — FRAMES has no partial credit. The judge\n * resolves strictly on the Answer value; wiki_links are a SOFT signal surfaced\n * in `detail` for the critic, never a hard pass criterion.\n *\n * Requires for a live run: the bench `.venv` with `datasets` installed and a\n * JUDGE_MODEL router key. For offline/CI verification set FRAMES_FIXTURES=1 to\n * load the committed fixtures (bench/fixtures/frames.json) — no HF download.\n */\n\nimport { execFile } from 'node:child_process'\nimport { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport { promisify } from 'node:util'\nimport type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'\n\nconst execFileAsync = promisify(execFile)\nconst BENCH_ROOT = fileURLToPath(new URL('../..', import.meta.url))\nconst PY = join(BENCH_ROOT, '.venv', 'bin', 'python')\nconst FIXTURES = join(BENCH_ROOT, 'fixtures', 'frames.json')\n\nconst DATASET = 'google/frames-benchmark'\n/** Pin the dataset revision: ids are derived from row order (no native id column),\n * so a reorder would break opts.ids selection + scorecard joins. */\nconst DATASET_REVISION = 'main'\nconst FINAL_ANSWER_SENTINEL = 'FINAL ANSWER:'\n\n/** Worker contract appended to every task prompt. Tier-1 parsing keys off the sentinel. */\nconst WORKER_CONTRACT = [\n '',\n 'Research the question using live web sources and answer it.',\n 'Cite the sources you used as full URLs, one per line, in a `CITATIONS:` block.',\n `End your response with a single final line: \\`${FINAL_ANSWER_SENTINEL} <answer>\\``,\n 'The answer after the sentinel must be the bare value only (no explanation on that line).',\n].join('\\n')\n\n/**\n * Typed seam for the future dynamic-topology research worker. The benchmark\n * adapter scores a plain `string` artifact (the BenchmarkAdapter contract); the\n * loop worker decodes its agent runs into a {@link ResearchAnswer} and serializes\n * `finalAnswer` (+ optional `CITATIONS:` block) into that string before judging.\n */\nexport interface ResearchTask {\n id: string\n question: string\n /** Gold short answer — judge resolves strictly against this. */\n gold: string\n /** Gold Wikipedia URLs — SOFT citation-coverage signal for the critic, never a hard gate. */\n goldSources: string[]\n /** FRAMES reasoning_types, e.g. 'numerical | temporal' — slices the scorecard by hop-type. */\n reasoningTypes: string\n}\n\nexport interface ResearchAnswer {\n finalAnswer: string\n citations: string[]\n}\n\ninterface FramesRow {\n Prompt: string\n Answer: string\n wiki_links: string\n reasoning_types: string\n}\n\ninterface FramesMeta {\n gold: string\n goldSources: string[]\n reasoningTypes: string\n rawPrompt: string\n}\n\n/** Run the bench venv python with a script on stdin; return stdout (throws on nonzero). */\nasync function py(script: string, args: string[] = []): Promise<string> {\n const { stdout } = await execFileAsync(PY, ['-c', script, ...args], {\n maxBuffer: 1024 * 1024 * 256,\n })\n return stdout\n}\n\nconst ARTICLES = new Set(['a', 'an', 'the'])\nconst UNIT_WORDS = new Set([\n 'years',\n 'year',\n 'months',\n 'month',\n 'days',\n 'day',\n 'people',\n 'percent',\n 'dollars',\n 'meters',\n 'metres',\n 'kilometers',\n 'kilometres',\n 'miles',\n 'km',\n 'm',\n])\n\nconst WRITTEN_NUMBERS: Record<string, number> = {\n zero: 0,\n one: 1,\n two: 2,\n three: 3,\n four: 4,\n five: 5,\n six: 6,\n seven: 7,\n eight: 8,\n nine: 9,\n ten: 10,\n eleven: 11,\n twelve: 12,\n thirteen: 13,\n fourteen: 14,\n fifteen: 15,\n sixteen: 16,\n seventeen: 17,\n eighteen: 18,\n nineteen: 19,\n twenty: 20,\n thirty: 30,\n forty: 40,\n fifty: 50,\n sixty: 60,\n seventy: 70,\n eighty: 80,\n ninety: 90,\n hundred: 100,\n thousand: 1000,\n million: 1_000_000,\n billion: 1_000_000_000,\n}\n\nconst MONTHS: Record<string, string> = {\n january: '01',\n february: '02',\n march: '03',\n april: '04',\n may: '05',\n june: '06',\n july: '07',\n august: '08',\n september: '09',\n october: '10',\n november: '11',\n december: '12',\n}\n\nconst SCALES = new Set(['hundred', 'thousand', 'million', 'billion'])\n\n/** Fold a run of written-number words into one integer (\"twenty eight\"→28, \"two hundred\"→200). */\nfunction composeWrittenRun(words: string[]): number {\n let total = 0\n let current = 0\n for (const w of words) {\n const v = WRITTEN_NUMBERS[w]\n if (v === undefined) continue\n if (w === 'hundred') {\n current = (current === 0 ? 1 : current) * 100\n } else if (SCALES.has(w)) {\n current = (current === 0 ? 1 : current) * v\n total += current\n current = 0\n } else {\n current += v\n }\n }\n return total + current\n}\n\n/** Canonicalize \"1,234\" / \"1.2 million\" / written numerals to a single numeric token. */\nfunction canonicalizeNumbers(s: string): string {\n // \"1,234,567\" → \"1234567\"\n let out = s.replace(/(\\d),(?=\\d{3}\\b)/g, '$1')\n // \"1.2 million\" / \"3 billion\" → expanded integer\n out = out.replace(/\\b(\\d+(?:\\.\\d+)?)\\s+(hundred|thousand|million|billion)\\b/g, (_m, num: string, scaleWord: string) => {\n const scale = WRITTEN_NUMBERS[scaleWord] ?? 1\n return String(Number(num) * scale)\n })\n // fold contiguous runs of written-number words into one integer\n out = out.replace(/\\b[a-z]+(?:[\\s-]+[a-z]+)*\\b/g, (run) => {\n const words = run.split(/[\\s-]+/)\n if (!words.every((w) => w in WRITTEN_NUMBERS)) return run\n return String(composeWrittenRun(words))\n })\n return out\n}\n\n/** \"March 3, 1879\" / \"3 March 1879\" → \"1879-03-03\"; year-only stays as the year. */\nfunction canonicalizeDates(s: string): string {\n let out = s.replace(\n /\\b(january|february|march|april|may|june|july|august|september|october|november|december)\\s+(\\d{1,2}),?\\s+(\\d{4})\\b/g,\n (_m, mon: string, day: string, year: string) => `${year}-${MONTHS[mon]}-${day.padStart(2, '0')}`,\n )\n out = out.replace(\n /\\b(\\d{1,2})\\s+(january|february|march|april|may|june|july|august|september|october|november|december)\\s+(\\d{4})\\b/g,\n (_m, day: string, mon: string, year: string) => `${year}-${MONTHS[mon]}-${day.padStart(2, '0')}`,\n )\n return out\n}\n\n/** Port of the SQuAD/GAIA normalize_answer routine, plus number/date canonicalization. */\nexport function normalizeAnswer(input: string): string {\n let s = input.toLowerCase()\n s = canonicalizeDates(s)\n s = canonicalizeNumbers(s)\n // strip punctuation (keep alphanumerics, ISO-date hyphens collapse to space-free below)\n s = s.replace(/[^\\w\\s-]/g, ' ')\n // tokenize, drop articles + trailing unit words, keep order\n const tokens = s\n .split(/\\s+/)\n .filter((t) => t.length > 0)\n .filter((t) => !ARTICLES.has(t))\n .filter((t) => !UNIT_WORDS.has(t))\n return tokens.join(' ').trim()\n}\n\n/** Tier-1 match: normalized equality OR normalized gold as a token-boundary substring. */\nfunction tier1Match(candidate: string, gold: string): boolean {\n const nc = normalizeAnswer(candidate)\n const ng = normalizeAnswer(gold)\n if (ng.length === 0) return false\n if (nc === ng) return true\n // token-boundary containment: gold appears as a whole-token run inside candidate\n const re = new RegExp(`(^|\\\\s)${ng.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')}(\\\\s|$)`)\n return re.test(nc)\n}\n\n/**\n * Parse the worker artifact into the final answer string.\n * Order: the `FINAL ANSWER:` sentinel first (deterministic-extraction discipline);\n * fall back to the last non-empty line. Returns '' when nothing is parseable\n * (fail-closed — never guess), which judge() counts as resolved=false.\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 t = (lines[i] ?? '').trim()\n if (t.length > 0) return t\n }\n return ''\n}\n\n/** Extract cited URLs from a `CITATIONS:` block and any bare URLs in the artifact. */\nexport function parseCitations(artifact: string): string[] {\n const urls = new Set<string>()\n for (const m of artifact.matchAll(/https?:\\/\\/[^\\s)<>\"']+/g)) {\n urls.add(m[0].replace(/[.,;]+$/, ''))\n }\n return [...urls]\n}\n\n/** Fraction of gold Wikipedia article slugs touched by the candidate's citations. SOFT signal. */\nfunction citationCoverage(citations: string[], goldSources: string[]): number {\n if (goldSources.length === 0) return 1\n const slug = (u: string) => {\n const m = u.match(/\\/wiki\\/([^#?]+)/)\n return m ? decodeURIComponent(m[1] ?? '').toLowerCase() : u.toLowerCase()\n }\n const got = new Set(citations.map(slug))\n let hit = 0\n for (const g of goldSources) if (got.has(slug(g))) hit += 1\n return hit / goldSources.length\n}\n\nconst JUDGE_PROMPT = (question: string, gold: string, candidate: string): string =>\n [\n 'You are a strict answer-equivalence checker for a factual question-answering benchmark.',\n 'Decide ONLY whether the candidate answer is semantically equivalent to the gold answer for this question.',\n 'It is CORRECT iff it contains the same factual value as the gold answer. Extra correct detail is fine.',\n 'A different value, a missing value, or a wrong value is INCORRECT.',\n '',\n `Question: ${question}`,\n `Gold answer: ${gold}`,\n `Candidate answer: ${candidate}`,\n '',\n 'Respond with ONLY a fenced JSON block and nothing else:',\n '```json',\n '{\"verdict\": \"correct\" | \"incorrect\"}',\n '```',\n ].join('\\n')\n\ninterface JudgeRouter {\n baseUrl: string\n key: string\n model: string\n}\n\nfunction judgeRouter(): JudgeRouter {\n const model = process.env.JUDGE_MODEL\n if (!model) throw new Error('JUDGE_MODEL is required for the FRAMES Tier-2 equivalence judge')\n const key = process.env.TANGLE_API_KEY\n if (!key) throw new Error('TANGLE_API_KEY is required for the FRAMES Tier-2 judge')\n const baseUrl = process.env.JUDGE_ROUTER_BASE ?? process.env.ROUTER_BASE ?? 'https://router.tangle.tools/v1'\n return { baseUrl, key, model }\n}\n\n/** Constrained binary equivalence gate. Pinned model, temperature 0; fail loud on unparseable output. */\nasync function tier2Judge(\n question: string,\n gold: string,\n candidate: string,\n router: JudgeRouter,\n): Promise<boolean> {\n const res = await fetch(`${router.baseUrl}/chat/completions`, {\n method: 'POST',\n headers: { 'content-type': 'application/json', authorization: `Bearer ${router.key}` },\n body: JSON.stringify({\n model: router.model,\n temperature: 0,\n seed: 0,\n messages: [{ role: 'user', content: JUDGE_PROMPT(question, gold, candidate) }],\n }),\n })\n if (!res.ok) {\n throw new Error(`FRAMES Tier-2 judge HTTP ${res.status}: ${(await res.text()).slice(0, 300)}`)\n }\n const body = (await res.json()) as { choices?: Array<{ message?: { content?: string } }> }\n const content = body.choices?.[0]?.message?.content\n if (typeof content !== 'string') {\n throw new Error(`FRAMES Tier-2 judge returned no message content: ${JSON.stringify(body).slice(0, 300)}`)\n }\n const fenced = content.match(/```(?:json)?\\s*([\\s\\S]*?)```/)\n const raw = (fenced ? fenced[1] : content)?.trim() ?? ''\n let parsed: { verdict?: unknown }\n try {\n parsed = JSON.parse(raw) as { verdict?: unknown }\n } catch {\n throw new Error(`FRAMES Tier-2 judge produced unparseable output (no JSON verdict): ${content.slice(0, 300)}`)\n }\n if (parsed.verdict === 'correct') return true\n if (parsed.verdict === 'incorrect') return false\n throw new Error(`FRAMES Tier-2 judge verdict not in {correct,incorrect}: ${JSON.stringify(parsed).slice(0, 200)}`)\n}\n\n/** FRAMES wiki_links is a python-repr list string, e.g. \"['https://…', 'https://…']\". */\nfunction parseWikiLinks(raw: string): string[] {\n if (!raw) return []\n const out: string[] = []\n for (const m of raw.matchAll(/https?:\\/\\/[^\\s'\"\\]]+/g)) out.push(m[0])\n return out\n}\n\nfunction rowToTask(row: FramesRow, index: number): BenchTask {\n const goldSources = parseWikiLinks(row.wiki_links)\n const meta: FramesMeta = {\n gold: row.Answer,\n goldSources,\n reasoningTypes: row.reasoning_types ?? '',\n rawPrompt: row.Prompt,\n }\n return {\n id: `frames-${index}`,\n split: 'test',\n prompt: row.Prompt + WORKER_CONTRACT,\n metadata: meta as unknown as Record<string, unknown>,\n }\n}\n\nfunction readMeta(task: BenchTask): FramesMeta {\n const md = task.metadata\n if (!md || typeof md.gold !== 'string') {\n throw new Error(`FRAMES task ${task.id} missing metadata.gold — loadTasks did not populate it`)\n }\n return md as unknown as FramesMeta\n}\n\nasync function loadFixtures(opts: LoadOptions): Promise<BenchTask[]> {\n const rows = JSON.parse(await readFile(FIXTURES, 'utf8')) as FramesRow[]\n console.log(`[frames] FRAMES_FIXTURES=1 — loading ${rows.length} committed fixtures (no HF download)`)\n let tasks = rows.map(rowToTask)\n if (opts.ids) {\n const want = new Set(opts.ids)\n tasks = tasks.filter((t) => want.has(t.id))\n } else if (opts.limit !== undefined) {\n tasks = tasks.slice(0, opts.limit)\n }\n return tasks\n}\n\nexport function createFramesAdapter(): BenchmarkAdapter {\n const fixturesMode = process.env.FRAMES_FIXTURES === '1'\n\n return {\n name: 'frames',\n\n async preflight() {\n // Tier-2 judge router config must be present in both modes — the loop's\n // citation-coverage stop gate is meaningless without the equivalence judge.\n judgeRouter()\n if (fixturesMode) {\n await readFile(FIXTURES, 'utf8').catch((err) => {\n throw new Error(`FRAMES_FIXTURES=1 but ${FIXTURES} unreadable: ${err instanceof Error ? err.message : err}`)\n })\n return\n }\n try {\n await py(\n `from datasets import load_dataset\nload_dataset(${JSON.stringify(DATASET)}, split='test', revision=${JSON.stringify(DATASET_REVISION)})\nprint('ok')`,\n )\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err)\n throw new Error(\n `frames preflight failed: ${msg}\\n` +\n `Fix: (1) python3 -m venv bench/.venv && bench/.venv/bin/pip install datasets ; ` +\n `(2) ensure network access to Hugging Face for ${DATASET} ; ` +\n `or set FRAMES_FIXTURES=1 to run against the committed fixtures offline.`,\n )\n }\n },\n\n async loadTasks(opts: LoadOptions = {}) {\n if (fixturesMode) return loadFixtures(opts)\n const limit = opts.limit ?? 10\n const script = `\nimport json, sys\nfrom datasets import load_dataset\nds = load_dataset(${JSON.stringify(DATASET)}, split='test', revision=${JSON.stringify(DATASET_REVISION)})\nids = set(json.loads(sys.argv[1])) if len(sys.argv) > 1 and sys.argv[1] else None\nout = []\nfor i, r in enumerate(ds):\n rid = f\"frames-{i}\"\n if ids is not None and rid not in ids:\n continue\n out.append({\n \"_index\": i,\n \"Prompt\": r.get(\"Prompt\", \"\"),\n \"Answer\": r.get(\"Answer\", \"\"),\n \"wiki_links\": str(r.get(\"wiki_links\", \"\")),\n \"reasoning_types\": str(r.get(\"reasoning_types\", \"\")),\n })\n if ids is None and len(out) >= ${limit}:\n break\nprint(json.dumps(out))\n`\n const stdout = await py(script, [opts.ids ? JSON.stringify(opts.ids) : ''])\n const rows = JSON.parse(stdout) as Array<FramesRow & { _index: number }>\n return rows.map((r) => rowToTask(r, r._index))\n },\n\n async goldArtifact(task: BenchTask) {\n // Gold artifact = the worker-contract serialization of the gold Answer, so\n // verify-judge proves gold→resolved through the SAME parse path the real\n // artifact takes (Tier-1 short-circuits with no model tokens).\n const meta = readMeta(task)\n return `${FINAL_ANSWER_SENTINEL} ${meta.gold}`\n },\n\n async judge(task: BenchTask, artifact: string): Promise<BenchScore> {\n const meta = readMeta(task)\n const finalAnswer = parseFinalAnswer(artifact)\n const citations = parseCitations(artifact)\n const coverage = citationCoverage(citations, meta.goldSources)\n\n if (finalAnswer.length === 0) {\n // Fail-closed: distinguish prompt-adherence failure from a wrong answer.\n return {\n resolved: false,\n score: 0,\n detail: JSON.stringify({\n tier: 'none',\n reason: 'no parseable answer',\n normalizedGold: normalizeAnswer(meta.gold),\n citationCoverage: coverage,\n }),\n }\n }\n\n // Tier 1 — free, deterministic.\n if (tier1Match(finalAnswer, meta.gold)) {\n return {\n resolved: true,\n score: 1,\n detail: JSON.stringify({\n tier: 1,\n normalizedAnswer: normalizeAnswer(finalAnswer),\n normalizedGold: normalizeAnswer(meta.gold),\n citationCoverage: coverage,\n }),\n }\n }\n\n // Tier 2 — constrained LLM equivalence gate (fail loud on unparseable output).\n const verdict = await tier2Judge(meta.rawPrompt, meta.gold, finalAnswer, judgeRouter())\n return {\n resolved: verdict,\n score: verdict ? 1 : 0,\n detail: JSON.stringify({\n tier: 2,\n normalizedAnswer: normalizeAnswer(finalAnswer),\n normalizedGold: normalizeAnswer(meta.gold),\n judgeVerdict: verdict ? 'correct' : 'incorrect',\n citationCoverage: coverage,\n }),\n }\n },\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-IZ5M6OAC.js
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
runVenvPython
|
|
3
|
-
} from "./chunk-WSKWVEQB.js";
|
|
4
|
-
|
|
5
|
-
// src/benchmarks/tau-bench-shared.ts
|
|
6
|
-
import { readFile, stat } from "fs/promises";
|
|
7
|
-
import { resolve } from "path";
|
|
8
|
-
var tauResultsOutput = {
|
|
9
|
-
parse(events) {
|
|
10
|
-
let text = "";
|
|
11
|
-
for (const ev of events) {
|
|
12
|
-
const d = ev?.data;
|
|
13
|
-
const t = d?.finalText ?? d?.text ?? d?.result;
|
|
14
|
-
if (typeof t === "string" && t.length > 0) text = t;
|
|
15
|
-
}
|
|
16
|
-
const fences = [...text.matchAll(/```(?:text|path|json)?\s*\n([\s\S]*?)```/g)];
|
|
17
|
-
return (fences.at(-1)?.[1] ?? text).trim();
|
|
18
|
-
}
|
|
19
|
-
};
|
|
20
|
-
async function assertPath(path, label, benchName) {
|
|
21
|
-
try {
|
|
22
|
-
await stat(path);
|
|
23
|
-
} catch (err) {
|
|
24
|
-
throw new Error(`${benchName}: missing ${label} at ${path} (${err instanceof Error ? err.message : err})`);
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
function benchDir(config) {
|
|
28
|
-
return process.env[config.dirEnv];
|
|
29
|
-
}
|
|
30
|
-
function benchDomain(config) {
|
|
31
|
-
return process.env[config.domainEnv] ?? config.defaultDomain;
|
|
32
|
-
}
|
|
33
|
-
function rowToTask(row, config, split) {
|
|
34
|
-
const meta = {
|
|
35
|
-
taskId: row.id,
|
|
36
|
-
domain: row.domain,
|
|
37
|
-
split,
|
|
38
|
-
userScenario: row.user_scenario,
|
|
39
|
-
description: row.description,
|
|
40
|
-
evaluationCriteria: row.evaluation_criteria
|
|
41
|
-
};
|
|
42
|
-
return {
|
|
43
|
-
id: row.id,
|
|
44
|
-
split,
|
|
45
|
-
prompt: [
|
|
46
|
-
config.taskIntro,
|
|
47
|
-
`Run this task in the official ${row.domain} domain.`,
|
|
48
|
-
"The benchmark is a simulated multi-turn user/tool conversation.",
|
|
49
|
-
"",
|
|
50
|
-
typeof row.user_scenario === "string" ? row.user_scenario : JSON.stringify(row.user_scenario ?? {}, null, 2),
|
|
51
|
-
"",
|
|
52
|
-
"Return the path to the official tau results.json or trajectory file containing this task run."
|
|
53
|
-
].join("\n"),
|
|
54
|
-
metadata: meta
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
function readMeta(task, benchName) {
|
|
58
|
-
const md = task.metadata;
|
|
59
|
-
if (!md || typeof md.taskId !== "string" || typeof md.domain !== "string") {
|
|
60
|
-
throw new Error(`${benchName} task ${task.id} missing metadata \u2014 loadTasks did not populate it`);
|
|
61
|
-
}
|
|
62
|
-
return md;
|
|
63
|
-
}
|
|
64
|
-
function selectRows(rows, opts, config, split) {
|
|
65
|
-
let tasks = rows.map((row) => rowToTask(row, config, split));
|
|
66
|
-
if (opts.ids) {
|
|
67
|
-
const want = new Set(opts.ids);
|
|
68
|
-
tasks = tasks.filter((task) => want.has(task.id));
|
|
69
|
-
} else if (opts.limit !== void 0) {
|
|
70
|
-
tasks = tasks.slice(0, opts.limit);
|
|
71
|
-
}
|
|
72
|
-
if (tasks.length === 0) throw new Error(`${config.name}: no tasks matched ${JSON.stringify(opts)}`);
|
|
73
|
-
return tasks;
|
|
74
|
-
}
|
|
75
|
-
async function loadFixtures(config, opts) {
|
|
76
|
-
const rows = JSON.parse(await readFile(config.fixturePath, "utf8"));
|
|
77
|
-
console.warn(`[${config.name}] ${config.fixturesEnv}=1 \u2014 loading ${rows.length} adapter fixtures`);
|
|
78
|
-
return selectRows(rows, opts, config, opts.split);
|
|
79
|
-
}
|
|
80
|
-
async function loadOfficialTasks(config, root, opts) {
|
|
81
|
-
const domain = benchDomain(config);
|
|
82
|
-
const script = `
|
|
83
|
-
import json, sys
|
|
84
|
-
from pathlib import Path
|
|
85
|
-
root = Path(sys.argv[1])
|
|
86
|
-
domain = sys.argv[2]
|
|
87
|
-
split = sys.argv[3] or None
|
|
88
|
-
sys.path.insert(0, str(root / "src"))
|
|
89
|
-
from tau2.registry import registry
|
|
90
|
-
loader = registry.get_tasks_loader(domain)
|
|
91
|
-
tasks = loader(split)
|
|
92
|
-
rows = []
|
|
93
|
-
for task in tasks:
|
|
94
|
-
row = task.model_dump(mode="json")
|
|
95
|
-
row["domain"] = domain
|
|
96
|
-
rows.append(row)
|
|
97
|
-
print(json.dumps(rows))
|
|
98
|
-
`;
|
|
99
|
-
const stdout = await runVenvPython(script, [root, domain, opts.split ?? ""]);
|
|
100
|
-
return selectRows(JSON.parse(stdout), opts, config, opts.split);
|
|
101
|
-
}
|
|
102
|
-
async function scoreOfficialTrajectory(root, meta, artifactPath) {
|
|
103
|
-
const script = `
|
|
104
|
-
import json, sys
|
|
105
|
-
from pathlib import Path
|
|
106
|
-
root = Path(sys.argv[1])
|
|
107
|
-
task_id = sys.argv[2]
|
|
108
|
-
artifact = Path(sys.argv[3])
|
|
109
|
-
sys.path.insert(0, str(root / "src"))
|
|
110
|
-
from tau2.data_model.simulation import Results
|
|
111
|
-
from tau2.scripts.evaluate_trajectories import compute_simulation_rewards
|
|
112
|
-
results = Results.load(artifact)
|
|
113
|
-
updated = compute_simulation_rewards(results)
|
|
114
|
-
scores = []
|
|
115
|
-
for sim in updated.simulations:
|
|
116
|
-
if sim.task_id == task_id and sim.reward_info is not None:
|
|
117
|
-
scores.append(float(sim.reward_info.reward))
|
|
118
|
-
if not scores:
|
|
119
|
-
raise SystemExit(f"no scored simulations for task_id={task_id} in {artifact}")
|
|
120
|
-
print(json.dumps({"count": len(scores), "score": sum(scores) / len(scores), "scores": scores}))
|
|
121
|
-
`;
|
|
122
|
-
const stdout = await runVenvPython(script, [root, meta.taskId, artifactPath], 0);
|
|
123
|
-
return JSON.parse(stdout.trim().split("\n").at(-1) ?? "{}");
|
|
124
|
-
}
|
|
125
|
-
function createTauBenchAdapter(config) {
|
|
126
|
-
const fixturesMode = process.env[config.fixturesEnv] === "1";
|
|
127
|
-
return {
|
|
128
|
-
name: config.name,
|
|
129
|
-
output: tauResultsOutput,
|
|
130
|
-
async preflight() {
|
|
131
|
-
if (fixturesMode) return;
|
|
132
|
-
const dir = benchDir(config);
|
|
133
|
-
if (!dir) {
|
|
134
|
-
throw new Error(`${config.dirEnv} is required. Fix: ${config.installHint}`);
|
|
135
|
-
}
|
|
136
|
-
await assertPath(`${dir}/src/tau2/registry.py`, "tau registry", config.name);
|
|
137
|
-
await loadOfficialTasks(config, dir, { limit: 1 });
|
|
138
|
-
},
|
|
139
|
-
async loadTasks(opts = {}) {
|
|
140
|
-
if (fixturesMode) return loadFixtures(config, opts);
|
|
141
|
-
const dir = benchDir(config);
|
|
142
|
-
if (!dir) throw new Error(`${config.dirEnv} is required to load official ${config.name} tasks`);
|
|
143
|
-
return loadOfficialTasks(config, dir, opts);
|
|
144
|
-
},
|
|
145
|
-
async goldArtifact() {
|
|
146
|
-
return void 0;
|
|
147
|
-
},
|
|
148
|
-
async judge(task, artifact) {
|
|
149
|
-
const dir = benchDir(config);
|
|
150
|
-
if (!dir) throw new Error(`${config.dirEnv} is required to judge ${config.name} trajectory artifacts`);
|
|
151
|
-
const meta = readMeta(task, config.name);
|
|
152
|
-
const artifactPath = resolve(artifact.trim());
|
|
153
|
-
await assertPath(artifactPath, "tau results/trajectory artifact", config.name);
|
|
154
|
-
const report = await scoreOfficialTrajectory(dir, meta, artifactPath);
|
|
155
|
-
const score = typeof report.score === "number" ? report.score : 0;
|
|
156
|
-
return {
|
|
157
|
-
resolved: score === 1,
|
|
158
|
-
score,
|
|
159
|
-
detail: JSON.stringify({ taskId: meta.taskId, domain: meta.domain, count: report.count })
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
};
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
export {
|
|
166
|
-
tauResultsOutput,
|
|
167
|
-
createTauBenchAdapter
|
|
168
|
-
};
|
|
169
|
-
//# sourceMappingURL=chunk-IZ5M6OAC.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/benchmarks/tau-bench-shared.ts"],"sourcesContent":["/**\n * Shared tau-bench adapter spine.\n *\n * tau2 and tau3 live in the same upstream repository/package namespace today:\n * `sierra-research/tau2-bench`, Python package `tau2`. Keep one implementation\n * for task loading and reward recomputation so the domain/version adapters only\n * choose env names, default domain, and fixture file.\n */\n\nimport { readFile, stat } from 'node:fs/promises'\nimport { resolve } from 'node:path'\nimport type { OutputAdapter } from '@tangle-network/agent-runtime/loops'\nimport { runVenvPython } from './_harness'\nimport type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'\n\nexport interface TauBenchConfig {\n name: string\n fixturePath: string\n fixturesEnv: string\n dirEnv: string\n domainEnv: string\n defaultDomain: string\n installHint: string\n taskIntro: string\n}\n\ninterface TauRow {\n id: string\n domain: string\n user_scenario?: unknown\n description?: unknown\n evaluation_criteria?: unknown\n}\n\ninterface TauMeta {\n taskId: string\n domain: string\n split?: string\n userScenario?: unknown\n description?: unknown\n evaluationCriteria?: unknown\n}\n\nexport const tauResultsOutput: 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 const fences = [...text.matchAll(/```(?:text|path|json)?\\s*\\n([\\s\\S]*?)```/g)]\n return (fences.at(-1)?.[1] ?? text).trim()\n },\n}\n\nasync function assertPath(path: string, label: string, benchName: string): Promise<void> {\n try {\n await stat(path)\n } catch (err) {\n throw new Error(`${benchName}: missing ${label} at ${path} (${err instanceof Error ? err.message : err})`)\n }\n}\n\nfunction benchDir(config: TauBenchConfig): string | undefined {\n return process.env[config.dirEnv]\n}\n\nfunction benchDomain(config: TauBenchConfig): string {\n return process.env[config.domainEnv] ?? config.defaultDomain\n}\n\nfunction rowToTask(row: TauRow, config: TauBenchConfig, split?: string): BenchTask {\n const meta: TauMeta = {\n taskId: row.id,\n domain: row.domain,\n split,\n userScenario: row.user_scenario,\n description: row.description,\n evaluationCriteria: row.evaluation_criteria,\n }\n return {\n id: row.id,\n split,\n prompt: [\n config.taskIntro,\n `Run this task in the official ${row.domain} domain.`,\n 'The benchmark is a simulated multi-turn user/tool conversation.',\n '',\n typeof row.user_scenario === 'string' ? row.user_scenario : JSON.stringify(row.user_scenario ?? {}, null, 2),\n '',\n 'Return the path to the official tau results.json or trajectory file containing this task run.',\n ].join('\\n'),\n metadata: meta as unknown as Record<string, unknown>,\n }\n}\n\nfunction readMeta(task: BenchTask, benchName: string): TauMeta {\n const md = task.metadata\n if (!md || typeof md.taskId !== 'string' || typeof md.domain !== 'string') {\n throw new Error(`${benchName} task ${task.id} missing metadata — loadTasks did not populate it`)\n }\n return md as unknown as TauMeta\n}\n\nfunction selectRows(rows: TauRow[], opts: LoadOptions, config: TauBenchConfig, split?: string): BenchTask[] {\n let tasks = rows.map((row) => rowToTask(row, config, split))\n if (opts.ids) {\n const want = new Set(opts.ids)\n tasks = tasks.filter((task) => want.has(task.id))\n } else if (opts.limit !== undefined) {\n tasks = tasks.slice(0, opts.limit)\n }\n if (tasks.length === 0) throw new Error(`${config.name}: no tasks matched ${JSON.stringify(opts)}`)\n return tasks\n}\n\nasync function loadFixtures(config: TauBenchConfig, opts: LoadOptions): Promise<BenchTask[]> {\n const rows = JSON.parse(await readFile(config.fixturePath, 'utf8')) as TauRow[]\n console.warn(`[${config.name}] ${config.fixturesEnv}=1 — loading ${rows.length} adapter fixtures`)\n return selectRows(rows, opts, config, opts.split)\n}\n\nasync function loadOfficialTasks(config: TauBenchConfig, root: string, opts: LoadOptions): Promise<BenchTask[]> {\n const domain = benchDomain(config)\n const script = `\nimport json, sys\nfrom pathlib import Path\nroot = Path(sys.argv[1])\ndomain = sys.argv[2]\nsplit = sys.argv[3] or None\nsys.path.insert(0, str(root / \"src\"))\nfrom tau2.registry import registry\nloader = registry.get_tasks_loader(domain)\ntasks = loader(split)\nrows = []\nfor task in tasks:\n row = task.model_dump(mode=\"json\")\n row[\"domain\"] = domain\n rows.append(row)\nprint(json.dumps(rows))\n`\n const stdout = await runVenvPython(script, [root, domain, opts.split ?? ''])\n return selectRows(JSON.parse(stdout) as TauRow[], opts, config, opts.split)\n}\n\nasync function scoreOfficialTrajectory(root: string, meta: TauMeta, artifactPath: string): Promise<Record<string, unknown>> {\n const script = `\nimport json, sys\nfrom pathlib import Path\nroot = Path(sys.argv[1])\ntask_id = sys.argv[2]\nartifact = Path(sys.argv[3])\nsys.path.insert(0, str(root / \"src\"))\nfrom tau2.data_model.simulation import Results\nfrom tau2.scripts.evaluate_trajectories import compute_simulation_rewards\nresults = Results.load(artifact)\nupdated = compute_simulation_rewards(results)\nscores = []\nfor sim in updated.simulations:\n if sim.task_id == task_id and sim.reward_info is not None:\n scores.append(float(sim.reward_info.reward))\nif not scores:\n raise SystemExit(f\"no scored simulations for task_id={task_id} in {artifact}\")\nprint(json.dumps({\"count\": len(scores), \"score\": sum(scores) / len(scores), \"scores\": scores}))\n`\n const stdout = await runVenvPython(script, [root, meta.taskId, artifactPath], 0)\n return JSON.parse(stdout.trim().split('\\n').at(-1) ?? '{}') as Record<string, unknown>\n}\n\nexport function createTauBenchAdapter(config: TauBenchConfig): BenchmarkAdapter {\n const fixturesMode = process.env[config.fixturesEnv] === '1'\n\n return {\n name: config.name,\n output: tauResultsOutput,\n\n async preflight() {\n if (fixturesMode) return\n const dir = benchDir(config)\n if (!dir) {\n throw new Error(`${config.dirEnv} is required. Fix: ${config.installHint}`)\n }\n await assertPath(`${dir}/src/tau2/registry.py`, 'tau registry', config.name)\n await loadOfficialTasks(config, dir, { limit: 1 })\n },\n\n async loadTasks(opts: LoadOptions = {}) {\n if (fixturesMode) return loadFixtures(config, opts)\n const dir = benchDir(config)\n if (!dir) throw new Error(`${config.dirEnv} is required to load official ${config.name} tasks`)\n return loadOfficialTasks(config, dir, opts)\n },\n\n async goldArtifact() {\n return undefined\n },\n\n async judge(task: BenchTask, artifact: string): Promise<BenchScore> {\n const dir = benchDir(config)\n if (!dir) throw new Error(`${config.dirEnv} is required to judge ${config.name} trajectory artifacts`)\n const meta = readMeta(task, config.name)\n const artifactPath = resolve(artifact.trim())\n await assertPath(artifactPath, 'tau results/trajectory artifact', config.name)\n const report = await scoreOfficialTrajectory(dir, meta, artifactPath)\n const score = typeof report.score === 'number' ? report.score : 0\n return {\n resolved: score === 1,\n score,\n detail: JSON.stringify({ taskId: meta.taskId, domain: meta.domain, count: report.count }),\n }\n },\n }\n}\n"],"mappings":"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","names":[]}
|
package/dist/chunk-JTHWEDEW.js
DELETED
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
// src/refine-loop.ts
|
|
2
|
-
var defaultDecide = (history) => history[history.length - 1]?.verdict?.valid === true;
|
|
3
|
-
async function runRefineLoop(spec) {
|
|
4
|
-
const rounds = Math.max(1, spec.rounds);
|
|
5
|
-
const decide = spec.decide ?? defaultDecide;
|
|
6
|
-
let ctxSet = false;
|
|
7
|
-
let ctx = void 0;
|
|
8
|
-
try {
|
|
9
|
-
if (spec.setup) {
|
|
10
|
-
ctx = await spec.setup();
|
|
11
|
-
ctxSet = true;
|
|
12
|
-
}
|
|
13
|
-
const history = [];
|
|
14
|
-
for (let r = 1; r <= rounds; r += 1) {
|
|
15
|
-
const prompt = spec.prompt(r, history, ctx);
|
|
16
|
-
const { artifact, note } = await spec.runShot(prompt, r, ctx);
|
|
17
|
-
const verdict = spec.judge ? await spec.judge(artifact, r) : void 0;
|
|
18
|
-
history.push({ round: r, prompt, artifact, verdict, note });
|
|
19
|
-
if (decide(history)) break;
|
|
20
|
-
}
|
|
21
|
-
const blind = history[0];
|
|
22
|
-
const final = history[history.length - 1];
|
|
23
|
-
return { rounds: history, blind, final, resolved: history.some((h) => h.verdict?.valid === true) };
|
|
24
|
-
} finally {
|
|
25
|
-
if (ctxSet && spec.teardown) await spec.teardown(ctx);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export {
|
|
30
|
-
runRefineLoop
|
|
31
|
-
};
|
|
32
|
-
//# sourceMappingURL=chunk-JTHWEDEW.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/refine-loop.ts"],"sourcesContent":["/**\n * runRefineLoop — the ONE shared k-shot loop (see docs/architecture.md §1, §12).\n *\n * It replaces the seven hand-rolled `for (round 1..k) { shot → judge → decide →\n * carry-forward }` copies across the workers (~700 LOC of duplicated skeleton).\n * The worker is an OPAQUE `runShot`; this loop owns iteration, carry-forward\n * steering, optional per-round judging + early stop, and round bookkeeping.\n *\n * Two carry-forward channels, both first-class (the extraction found both in the\n * wild and they must stay pluggable):\n * - EXECUTION CONTEXT (`Ctx`): created once by `setup`, threaded to every shot,\n * torn down by `teardown`. This is how filesystem/session state carries — a\n * cloned repo whose edits persist (SWE refine), a shared sandbox box whose\n * session persists (sandbox research), or a scratch dir.\n * - PROMPT (`prompt(round, history, ctx)`): how textual state carries — round 1\n * is the blind prompt; rounds 2+ fold prior rounds' artifacts + a directive.\n *\n * Judging is OPTIONAL: workers that run all k rounds and let the orchestrator\n * judge omit `judge`/`decide` (the loop runs to budget); a loop that should stop\n * on the first valid answer wires `judge` (default `decide` = stop-on-valid).\n *\n * This is the inference-timescale instance of the spine's atom: `runShot` is the\n * worker Agent's `act→Output`; `prompt` is the driver Agent's `act→steer`. It is\n * deliberately corpus-agnostic — callers map `RefineLoopResult` to a RunRecord.\n */\n\n/** Minimal per-round verdict — `valid` gates early-stop, `score` is informational. */\nexport interface RoundVerdict {\n valid: boolean\n score?: number\n}\n\nexport interface RoundRecord<Artifact> {\n /** 1-based round index. */\n round: number\n prompt: string\n artifact: Artifact\n /** Present only when a `judge` is wired. */\n verdict?: RoundVerdict\n /** Non-fatal note (e.g. a liveness backstop fired this round). */\n note?: string\n}\n\nexport interface RefineLoopSpec<Artifact, Ctx = void> {\n /** Max shots. Always ≥ 1. */\n rounds: number\n /** Build the per-task execution context once (clone repo / create box / mkdtemp). */\n setup?: () => Promise<Ctx>\n /** Round `r`'s prompt. `r === 1` is the blind prompt; `r > 1` carries `history`. */\n prompt: (round: number, history: ReadonlyArray<RoundRecord<Artifact>>, ctx: Ctx) => string\n /** Run ONE shot — the opaque worker (local spawn / sandbox stream / router chat). */\n runShot: (\n prompt: string,\n round: number,\n ctx: Ctx,\n ) => Promise<{ artifact: Artifact; note?: string }>\n /** Optional per-round judge. Omit to run all `rounds` (orchestrator judges later). */\n judge?: (artifact: Artifact, round: number) => Promise<RoundVerdict>\n /** Stop after this round? Default: stop once a round's verdict is valid (else run to budget). */\n decide?: (history: ReadonlyArray<RoundRecord<Artifact>>) => boolean\n /** Always runs (even on throw) when `setup` ran. */\n teardown?: (ctx: Ctx) => Promise<void>\n}\n\nexport interface RefineLoopResult<Artifact> {\n /** Every executed round in order. */\n rounds: RoundRecord<Artifact>[]\n /** Round 1 — the blind artifact. */\n blind: RoundRecord<Artifact>\n /** The last executed round. */\n final: RoundRecord<Artifact>\n /** True iff any round was judged valid (only meaningful when `judge` is wired). */\n resolved: boolean\n}\n\nconst defaultDecide = <Artifact>(history: ReadonlyArray<RoundRecord<Artifact>>): boolean =>\n history[history.length - 1]?.verdict?.valid === true\n\nexport async function runRefineLoop<Artifact, Ctx = void>(\n spec: RefineLoopSpec<Artifact, Ctx>,\n): Promise<RefineLoopResult<Artifact>> {\n const rounds = Math.max(1, spec.rounds)\n const decide = spec.decide ?? defaultDecide\n let ctxSet = false\n let ctx = undefined as Ctx\n try {\n if (spec.setup) {\n ctx = await spec.setup()\n ctxSet = true\n }\n const history: RoundRecord<Artifact>[] = []\n for (let r = 1; r <= rounds; r += 1) {\n const prompt = spec.prompt(r, history, ctx)\n const { artifact, note } = await spec.runShot(prompt, r, ctx)\n const verdict = spec.judge ? await spec.judge(artifact, r) : undefined\n history.push({ round: r, prompt, artifact, verdict, note })\n if (decide(history)) break\n }\n // The loop runs ≥ 1 round, so history is non-empty.\n const blind = history[0] as RoundRecord<Artifact>\n const final = history[history.length - 1] as RoundRecord<Artifact>\n return { rounds: history, blind, final, resolved: history.some((h) => h.verdict?.valid === true) }\n } finally {\n if (ctxSet && spec.teardown) await spec.teardown(ctx)\n }\n}\n"],"mappings":";AA2EA,IAAM,gBAAgB,CAAW,YAC/B,QAAQ,QAAQ,SAAS,CAAC,GAAG,SAAS,UAAU;AAElD,eAAsB,cACpB,MACqC;AACrC,QAAM,SAAS,KAAK,IAAI,GAAG,KAAK,MAAM;AACtC,QAAM,SAAS,KAAK,UAAU;AAC9B,MAAI,SAAS;AACb,MAAI,MAAM;AACV,MAAI;AACF,QAAI,KAAK,OAAO;AACd,YAAM,MAAM,KAAK,MAAM;AACvB,eAAS;AAAA,IACX;AACA,UAAM,UAAmC,CAAC;AAC1C,aAAS,IAAI,GAAG,KAAK,QAAQ,KAAK,GAAG;AACnC,YAAM,SAAS,KAAK,OAAO,GAAG,SAAS,GAAG;AAC1C,YAAM,EAAE,UAAU,KAAK,IAAI,MAAM,KAAK,QAAQ,QAAQ,GAAG,GAAG;AAC5D,YAAM,UAAU,KAAK,QAAQ,MAAM,KAAK,MAAM,UAAU,CAAC,IAAI;AAC7D,cAAQ,KAAK,EAAE,OAAO,GAAG,QAAQ,UAAU,SAAS,KAAK,CAAC;AAC1D,UAAI,OAAO,OAAO,EAAG;AAAA,IACvB;AAEA,UAAM,QAAQ,QAAQ,CAAC;AACvB,UAAM,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AACxC,WAAO,EAAE,QAAQ,SAAS,OAAO,OAAO,UAAU,QAAQ,KAAK,CAAC,MAAM,EAAE,SAAS,UAAU,IAAI,EAAE;AAAA,EACnG,UAAE;AACA,QAAI,UAAU,KAAK,SAAU,OAAM,KAAK,SAAS,GAAG;AAAA,EACtD;AACF;","names":[]}
|
package/dist/chunk-K3BQGZCT.js
DELETED
|
@@ -1,221 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
benchRoot,
|
|
3
|
-
preflightVenvImports,
|
|
4
|
-
readJsonReport,
|
|
5
|
-
runStagedJudge,
|
|
6
|
-
stageFile,
|
|
7
|
-
venvPython
|
|
8
|
-
} from "./chunk-WSKWVEQB.js";
|
|
9
|
-
|
|
10
|
-
// src/benchmarks/aec-bench.ts
|
|
11
|
-
import { readFile } from "fs/promises";
|
|
12
|
-
import { join } from "path";
|
|
13
|
-
var FIXTURES = join(benchRoot, "fixtures", "aec-bench.json");
|
|
14
|
-
var REPO = "TheodoreGalanos/aec-bench";
|
|
15
|
-
var RAW = `https://raw.githubusercontent.com/${REPO}/main`;
|
|
16
|
-
var TREE = `https://api.github.com/repos/${REPO}/git/trees/main?recursive=1`;
|
|
17
|
-
var verifyPathPattern = /^tasks\/(.+)\/tests\/verify\.py$/;
|
|
18
|
-
var DEFAULT_LIMIT = 10;
|
|
19
|
-
function recordToTask(rec) {
|
|
20
|
-
const meta = {
|
|
21
|
-
taskId: rec.id,
|
|
22
|
-
discipline: rec.discipline,
|
|
23
|
-
taskToml: rec.task_toml,
|
|
24
|
-
verifyPy: rec.verify_py,
|
|
25
|
-
goldenPassMd: rec.golden_pass_md
|
|
26
|
-
};
|
|
27
|
-
return {
|
|
28
|
-
id: rec.id,
|
|
29
|
-
split: rec.discipline,
|
|
30
|
-
// instruction.md is fully self-contained and already specifies the exact JSON
|
|
31
|
-
// output schema + the "write to /workspace/output.md" contract the verifier
|
|
32
|
-
// keys off — we pass it through verbatim so the verify.py extractor matches.
|
|
33
|
-
prompt: rec.instruction,
|
|
34
|
-
metadata: meta
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
function readMeta(task) {
|
|
38
|
-
const md = task.metadata;
|
|
39
|
-
if (!md || typeof md.verifyPy !== "string" || typeof md.taskId !== "string") {
|
|
40
|
-
throw new Error(`aec-bench task ${task.id} missing verifier metadata \u2014 loadTasks did not populate it`);
|
|
41
|
-
}
|
|
42
|
-
return md;
|
|
43
|
-
}
|
|
44
|
-
async function fetchText(url) {
|
|
45
|
-
const res = await fetch(url);
|
|
46
|
-
if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`);
|
|
47
|
-
return res.text();
|
|
48
|
-
}
|
|
49
|
-
async function fetchTextOrNull(url) {
|
|
50
|
-
const res = await fetch(url);
|
|
51
|
-
if (res.status === 404) return null;
|
|
52
|
-
if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`);
|
|
53
|
-
return res.text();
|
|
54
|
-
}
|
|
55
|
-
async function listAllInstances() {
|
|
56
|
-
const res = await fetch(TREE);
|
|
57
|
-
if (!res.ok) throw new Error(`aec-bench tree ${res.status}: ${TREE}`);
|
|
58
|
-
const { tree } = await res.json();
|
|
59
|
-
const ids = [];
|
|
60
|
-
for (const entry of tree) {
|
|
61
|
-
const m = verifyPathPattern.exec(entry.path);
|
|
62
|
-
if (m?.[1]) ids.push(m[1]);
|
|
63
|
-
}
|
|
64
|
-
return ids;
|
|
65
|
-
}
|
|
66
|
-
async function fetchInstance(id) {
|
|
67
|
-
const base = `${RAW}/tasks/${id}`;
|
|
68
|
-
const verify = await fetch(`${base}/tests/verify.py`);
|
|
69
|
-
if (verify.status === 404) return null;
|
|
70
|
-
if (!verify.ok) throw new Error(`aec-bench fetch ${verify.status}: ${id}/tests/verify.py`);
|
|
71
|
-
const [instruction, task_toml, golden_pass_md] = await Promise.all([
|
|
72
|
-
fetchText(`${base}/instruction.md`),
|
|
73
|
-
fetchText(`${base}/task.toml`),
|
|
74
|
-
fetchTextOrNull(`${base}/tests/fixtures/golden_pass.md`)
|
|
75
|
-
]);
|
|
76
|
-
return {
|
|
77
|
-
id,
|
|
78
|
-
discipline: id.split("/")[0] ?? "",
|
|
79
|
-
instruction,
|
|
80
|
-
task_toml,
|
|
81
|
-
verify_py: await verify.text(),
|
|
82
|
-
golden_pass_md
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
function selectFixtures(records, opts) {
|
|
86
|
-
let tasks = records.map(recordToTask);
|
|
87
|
-
if (opts.split) tasks = tasks.filter((t) => t.split === opts.split);
|
|
88
|
-
if (opts.ids) {
|
|
89
|
-
const want = new Set(opts.ids);
|
|
90
|
-
tasks = tasks.filter((t) => want.has(t.id));
|
|
91
|
-
} else if (opts.limit !== void 0) {
|
|
92
|
-
tasks = tasks.slice(0, opts.limit);
|
|
93
|
-
}
|
|
94
|
-
return tasks;
|
|
95
|
-
}
|
|
96
|
-
async function loadFixtures(opts) {
|
|
97
|
-
const records = JSON.parse(await readFile(FIXTURES, "utf8"));
|
|
98
|
-
console.warn(
|
|
99
|
-
`[aec-bench] AEC_FIXTURES=1 \u2014 loading ${records.length} committed fixtures from ${FIXTURES} (no GitHub fetch)`
|
|
100
|
-
);
|
|
101
|
-
return selectFixtures(records, opts);
|
|
102
|
-
}
|
|
103
|
-
async function loadLive(opts) {
|
|
104
|
-
if (opts.ids) {
|
|
105
|
-
const records2 = [];
|
|
106
|
-
for (const id of opts.ids) {
|
|
107
|
-
const rec = await fetchInstance(id);
|
|
108
|
-
if (!rec) throw new Error(`aec-bench: ${id} has no tests/verify.py (seed-only or wrong id)`);
|
|
109
|
-
records2.push(rec);
|
|
110
|
-
}
|
|
111
|
-
return records2.map(recordToTask);
|
|
112
|
-
}
|
|
113
|
-
const limit = opts.limit ?? DEFAULT_LIMIT;
|
|
114
|
-
let ids = await listAllInstances();
|
|
115
|
-
if (opts.split) ids = ids.filter((id) => id.startsWith(`${opts.split}/`));
|
|
116
|
-
const records = [];
|
|
117
|
-
for (const id of ids) {
|
|
118
|
-
if (records.length >= limit) break;
|
|
119
|
-
try {
|
|
120
|
-
const rec = await fetchInstance(id);
|
|
121
|
-
if (rec) records.push(rec);
|
|
122
|
-
} catch (err) {
|
|
123
|
-
console.warn(`[aec-bench] skipping ${id}: ${err instanceof Error ? err.message : String(err)}`);
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
if (records.length === 0) {
|
|
127
|
-
throw new Error(
|
|
128
|
-
`aec-bench loadTasks found no runnable instances for ${JSON.stringify(opts)} (no tests/verify.py matched the requested split). Set AEC_FIXTURES=1 to run offline.`
|
|
129
|
-
);
|
|
130
|
-
}
|
|
131
|
-
return records.map(recordToTask);
|
|
132
|
-
}
|
|
133
|
-
async function runVerifier(meta, artifact) {
|
|
134
|
-
return runStagedJudge({
|
|
135
|
-
tmpPrefix: "aecbench-",
|
|
136
|
-
timeoutMs: 12e4,
|
|
137
|
-
async stage(dir) {
|
|
138
|
-
await Promise.all([
|
|
139
|
-
stageFile(join(dir, "output.md"), artifact),
|
|
140
|
-
stageFile(join(dir, "verify.py"), meta.verifyPy)
|
|
141
|
-
]);
|
|
142
|
-
},
|
|
143
|
-
bin: venvPython,
|
|
144
|
-
argv: (dir) => [join(dir, "verify.py"), "--input", join(dir, "output.md"), "--output", join(dir, "reward.json")],
|
|
145
|
-
async parseReport(dir) {
|
|
146
|
-
const report = await readJsonReport(join(dir, "reward.json"));
|
|
147
|
-
const reward = report.reward;
|
|
148
|
-
if (typeof reward !== "number" || !Number.isFinite(reward)) {
|
|
149
|
-
throw new Error(`aec-bench verify.py wrote no numeric reward for ${meta.taskId}: ${JSON.stringify(report)}`);
|
|
150
|
-
}
|
|
151
|
-
const details = await readFile(join(dir, "details.json"), "utf8").then(
|
|
152
|
-
(s) => JSON.parse(s),
|
|
153
|
-
() => ({})
|
|
154
|
-
);
|
|
155
|
-
const score = Math.max(0, Math.min(1, reward));
|
|
156
|
-
return {
|
|
157
|
-
// resolved = full credit (all fields within tolerance), matching aec-bench's perfect_rate.
|
|
158
|
-
resolved: score >= 1,
|
|
159
|
-
score,
|
|
160
|
-
detail: JSON.stringify({ taskId: meta.taskId, discipline: meta.discipline, reward, fields: details })
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
}
|
|
165
|
-
function createAecBenchAdapter() {
|
|
166
|
-
const fixturesMode = process.env.AEC_FIXTURES === "1";
|
|
167
|
-
return {
|
|
168
|
-
name: "aec-bench",
|
|
169
|
-
async preflight() {
|
|
170
|
-
await preflightVenvImports({
|
|
171
|
-
modules: ["math", "json", "re"],
|
|
172
|
-
requireDocker: false,
|
|
173
|
-
fix: "Fix: python3 -m venv bench/.venv (verify.py only needs the stdlib \u2014 no pip install)."
|
|
174
|
-
});
|
|
175
|
-
if (fixturesMode) {
|
|
176
|
-
await readFile(FIXTURES, "utf8").catch((err) => {
|
|
177
|
-
throw new Error(`AEC_FIXTURES=1 but ${FIXTURES} unreadable: ${err instanceof Error ? err.message : err}`);
|
|
178
|
-
});
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const res = await fetch(`${RAW}/README.md`, { method: "HEAD" }).catch((err) => {
|
|
182
|
-
throw new Error(
|
|
183
|
-
`aec-bench preflight failed reaching ${RAW}: ${err instanceof Error ? err.message : err}
|
|
184
|
-
Fix: ensure network access to raw.githubusercontent.com, or set AEC_FIXTURES=1 to run offline.`
|
|
185
|
-
);
|
|
186
|
-
});
|
|
187
|
-
if (!res.ok) {
|
|
188
|
-
throw new Error(
|
|
189
|
-
`aec-bench preflight: ${REPO} README HEAD ${res.status}. Set AEC_FIXTURES=1 to run against committed fixtures.`
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
},
|
|
193
|
-
async loadTasks(opts = {}) {
|
|
194
|
-
if (fixturesMode) return loadFixtures(opts);
|
|
195
|
-
try {
|
|
196
|
-
return await loadLive(opts);
|
|
197
|
-
} catch (err) {
|
|
198
|
-
if (err instanceof Error && /fetch \d|ENOTFOUND|getaddrinfo|network/i.test(err.message)) {
|
|
199
|
-
console.warn(
|
|
200
|
-
`[aec-bench] live fetch failed (${err.message.slice(0, 160)}); falling back to committed fixtures at ${FIXTURES}`
|
|
201
|
-
);
|
|
202
|
-
return loadFixtures(opts);
|
|
203
|
-
}
|
|
204
|
-
throw err;
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
async goldArtifact(task) {
|
|
208
|
-
const meta = readMeta(task);
|
|
209
|
-
return meta.goldenPassMd ?? void 0;
|
|
210
|
-
},
|
|
211
|
-
async judge(task, artifact) {
|
|
212
|
-
const meta = readMeta(task);
|
|
213
|
-
return runVerifier(meta, artifact);
|
|
214
|
-
}
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
export {
|
|
219
|
-
createAecBenchAdapter
|
|
220
|
-
};
|
|
221
|
-
//# sourceMappingURL=chunk-K3BQGZCT.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/benchmarks/aec-bench.ts"],"sourcesContent":["/**\n * AEC-Bench adapter (TheodoreGalanos/aec-bench, MIT) — closed-form\n * Architecture/Engineering/Construction calculation tasks. Worker artifact = a\n * markdown solution ending in a fenced ```json block with the required numeric\n * fields. Judge = the task's OWN `tests/verify.py`, run with python3: it\n * recomputes ground truth from the embedded engineering formulas, extracts the\n * last JSON block from the artifact, scores each field by math.isclose within a\n * per-field rel_tol, and writes {\"reward\": mean} + per-field details.json.\n * GRADED / partial-credit, FULLY DETERMINISTIC — no LLM judge.\n *\n * Distinct from the multimodal nomic-ai/aec-bench; this is the deterministic\n * calculation platform. The runnable-instance verify.py only needs python3 (no\n * Docker, no Harbor) for the pure-calc disciplines, so the local gate runs at\n * conc<=2 without a container backend.\n *\n * Requires for a live run: network to raw.githubusercontent.com /\n * api.github.com (the in-repo tasks tree) + a python3 interpreter (the bench\n * venv) to run verify.py. For offline/CI, set AEC_FIXTURES=1 to load the\n * committed fixtures (bench/fixtures/aec-bench.json) — never a silent fallback.\n */\n\nimport { readFile } from 'node:fs/promises'\nimport { join } from 'node:path'\nimport { benchRoot, preflightVenvImports, readJsonReport, runStagedJudge, stageFile, venvPython } from './_harness'\nimport type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'\n\nconst FIXTURES = join(benchRoot, 'fixtures', 'aec-bench.json')\n\nconst REPO = 'TheodoreGalanos/aec-bench'\nconst RAW = `https://raw.githubusercontent.com/${REPO}/main`\nconst TREE = `https://api.github.com/repos/${REPO}/git/trees/main?recursive=1`\n\n/** Matches every runnable-instance task id at ANY depth under tasks/. */\nconst verifyPathPattern = /^tasks\\/(.+)\\/tests\\/verify\\.py$/\n\n/** Default cap on tasks enumerated before a `limit` is applied. */\nconst DEFAULT_LIMIT = 10\n\ninterface AecRecord {\n /** Canonical task id `<discipline>/<task>`, e.g. 'electrical/catenary-sag'. */\n id: string\n discipline: string\n /** instruction.md — the self-contained prompt (table + required outputs + JSON schema). */\n instruction: string\n /** task.toml — metadata/difficulty/timeouts (carried for trace context). */\n task_toml: string\n /** tests/verify.py — the deterministic verifier (recomputes GT, scores fields). */\n verify_py: string\n /** tests/fixtures/golden_pass.md — the oracle artifact that scores reward 1.0,\n * when the task ships one. Null when the task only ships a non-md ground truth\n * (e.g. tests/ground_truth.json); the judge never needs it, only goldArtifact does. */\n golden_pass_md: string | null\n}\n\ninterface AecMeta {\n taskId: string\n discipline: string\n taskToml: string\n verifyPy: string\n goldenPassMd: string | null\n}\n\nfunction recordToTask(rec: AecRecord): BenchTask {\n const meta: AecMeta = {\n taskId: rec.id,\n discipline: rec.discipline,\n taskToml: rec.task_toml,\n verifyPy: rec.verify_py,\n goldenPassMd: rec.golden_pass_md,\n }\n return {\n id: rec.id,\n split: rec.discipline,\n // instruction.md is fully self-contained and already specifies the exact JSON\n // output schema + the \"write to /workspace/output.md\" contract the verifier\n // keys off — we pass it through verbatim so the verify.py extractor matches.\n prompt: rec.instruction,\n metadata: meta as unknown as Record<string, unknown>,\n }\n}\n\nfunction readMeta(task: BenchTask): AecMeta {\n const md = task.metadata\n // Gold is optional (goldenPassMd may be null) — only the verifier + id are required.\n if (!md || typeof md.verifyPy !== 'string' || typeof md.taskId !== 'string') {\n throw new Error(`aec-bench task ${task.id} missing verifier metadata — loadTasks did not populate it`)\n }\n return md as unknown as AecMeta\n}\n\nasync function fetchText(url: string): Promise<string> {\n const res = await fetch(url)\n if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`)\n return res.text()\n}\n\n/** Like fetchText but returns null on a 404 (absent optional file); throws on any other non-OK. */\nasync function fetchTextOrNull(url: string): Promise<string | null> {\n const res = await fetch(url)\n if (res.status === 404) return null\n if (!res.ok) throw new Error(`aec-bench fetch ${res.status}: ${url}`)\n return res.text()\n}\n\ninterface GitTree {\n tree: Array<{ path: string; type: string }>\n}\n\n/**\n * One recursive git-tree call enumerates EVERY runnable-instance id at any depth:\n * a task is runnable iff it ships tests/verify.py. The captured group is the id\n * `tasks/<id>/tests/verify.py` → `<id>` (e.g. 'electrical/pf-droop', or a deeper\n * '<discipline>/<family>/<task>'). Throws loud on a non-OK tree response.\n */\nasync function listAllInstances(): Promise<string[]> {\n const res = await fetch(TREE)\n if (!res.ok) throw new Error(`aec-bench tree ${res.status}: ${TREE}`)\n const { tree } = (await res.json()) as GitTree\n const ids: string[] = []\n for (const entry of tree) {\n const m = verifyPathPattern.exec(entry.path)\n if (m?.[1]) ids.push(m[1])\n }\n return ids\n}\n\n/**\n * Fetch one task's instruction.md + task.toml + tests/verify.py + golden_pass.md.\n * Returns null when the dir is a SEED (no runnable verify.py) so enumeration can\n * skip it without faking a task. Gold is OPTIONAL — a task that ships a non-md\n * ground truth (e.g. tests/ground_truth.json) yields golden_pass_md=null; the\n * deterministic judge needs only verify.py.\n */\nasync function fetchInstance(id: string): Promise<AecRecord | null> {\n const base = `${RAW}/tasks/${id}`\n const verify = await fetch(`${base}/tests/verify.py`)\n if (verify.status === 404) return null\n if (!verify.ok) throw new Error(`aec-bench fetch ${verify.status}: ${id}/tests/verify.py`)\n const [instruction, task_toml, golden_pass_md] = await Promise.all([\n fetchText(`${base}/instruction.md`),\n fetchText(`${base}/task.toml`),\n fetchTextOrNull(`${base}/tests/fixtures/golden_pass.md`),\n ])\n return {\n id,\n discipline: id.split('/')[0] ?? '',\n instruction,\n task_toml,\n verify_py: await verify.text(),\n golden_pass_md,\n }\n}\n\nfunction selectFixtures(records: AecRecord[], opts: LoadOptions): BenchTask[] {\n let tasks = records.map(recordToTask)\n if (opts.split) tasks = tasks.filter((t) => t.split === opts.split)\n if (opts.ids) {\n const want = new Set(opts.ids)\n tasks = tasks.filter((t) => want.has(t.id))\n } else if (opts.limit !== undefined) {\n tasks = tasks.slice(0, opts.limit)\n }\n return tasks\n}\n\nasync function loadFixtures(opts: LoadOptions): Promise<BenchTask[]> {\n const records = JSON.parse(await readFile(FIXTURES, 'utf8')) as AecRecord[]\n console.warn(\n `[aec-bench] AEC_FIXTURES=1 — loading ${records.length} committed fixtures from ${FIXTURES} (no GitHub fetch)`,\n )\n return selectFixtures(records, opts)\n}\n\n/** Enumerate live tasks: explicit ids (each required — throws on a bad id), or a\n * capped slice of the recursive tree (optionally filtered to one split). Per-task\n * resilient: a single fetch failure warns + SKIPS that task, never aborting the\n * batch. Skips seed dirs (no verify.py) — never fabricates. */\nasync function loadLive(opts: LoadOptions): Promise<BenchTask[]> {\n if (opts.ids) {\n const records: AecRecord[] = []\n for (const id of opts.ids) {\n const rec = await fetchInstance(id)\n if (!rec) throw new Error(`aec-bench: ${id} has no tests/verify.py (seed-only or wrong id)`)\n records.push(rec)\n }\n return records.map(recordToTask)\n }\n const limit = opts.limit ?? DEFAULT_LIMIT\n let ids = await listAllInstances()\n if (opts.split) ids = ids.filter((id) => id.startsWith(`${opts.split}/`))\n const records: AecRecord[] = []\n for (const id of ids) {\n if (records.length >= limit) break\n try {\n const rec = await fetchInstance(id)\n if (rec) records.push(rec)\n } catch (err) {\n // One bad task must NEVER abort the batch — warn and skip it.\n console.warn(`[aec-bench] skipping ${id}: ${err instanceof Error ? err.message : String(err)}`)\n }\n }\n if (records.length === 0) {\n throw new Error(\n `aec-bench loadTasks found no runnable instances for ${JSON.stringify(opts)} ` +\n `(no tests/verify.py matched the requested split). Set AEC_FIXTURES=1 to run offline.`,\n )\n }\n return records.map(recordToTask)\n}\n\n/**\n * Run the task's own verify.py with python3 over the artifact via the shared\n * staged-judge spine (mkdtemp → stage → spawn → parseReport → cleanup). verify.py\n * writes {\"reward\": mean} to --output and per-field details.json as a sibling. We\n * read both: reward → graded score; details → sub-scores for the trace-analyst.\n * Fail loud if the verifier never wrote a numeric reward (a crashed verifier is\n * NOT a silent 0 — verify.py's own except-trap writes reward 0.0, so an absent /\n * non-numeric reward.json is a real bug, surfaced by readJsonReport).\n */\nasync function runVerifier(meta: AecMeta, artifact: string): Promise<BenchScore> {\n return runStagedJudge({\n tmpPrefix: 'aecbench-',\n timeoutMs: 120_000,\n async stage(dir) {\n await Promise.all([\n stageFile(join(dir, 'output.md'), artifact),\n stageFile(join(dir, 'verify.py'), meta.verifyPy),\n ])\n },\n bin: venvPython,\n argv: (dir) => [join(dir, 'verify.py'), '--input', join(dir, 'output.md'), '--output', join(dir, 'reward.json')],\n async parseReport(dir) {\n const report = await readJsonReport<{ reward?: number }>(join(dir, 'reward.json'))\n const reward = report.reward\n if (typeof reward !== 'number' || !Number.isFinite(reward)) {\n throw new Error(`aec-bench verify.py wrote no numeric reward for ${meta.taskId}: ${JSON.stringify(report)}`)\n }\n const details = await readFile(join(dir, 'details.json'), 'utf8').then(\n (s) => JSON.parse(s) as Record<string, number>,\n () => ({}),\n )\n const score = Math.max(0, Math.min(1, reward))\n return {\n // resolved = full credit (all fields within tolerance), matching aec-bench's perfect_rate.\n resolved: score >= 1,\n score,\n detail: JSON.stringify({ taskId: meta.taskId, discipline: meta.discipline, reward, fields: details }),\n }\n },\n })\n}\n\nexport function createAecBenchAdapter(): BenchmarkAdapter {\n const fixturesMode = process.env.AEC_FIXTURES === '1'\n\n return {\n name: 'aec-bench',\n\n async preflight() {\n // The verifier is python3 over the stdlib (math/json/re) — no pip install.\n // Reuse the shared import-probe so the bench venv interpreter is proven to\n // exist + run before any judge spawns verify.py.\n await preflightVenvImports({\n modules: ['math', 'json', 're'],\n requireDocker: false,\n fix: 'Fix: python3 -m venv bench/.venv (verify.py only needs the stdlib — no pip install).',\n })\n if (fixturesMode) {\n await readFile(FIXTURES, 'utf8').catch((err) => {\n throw new Error(`AEC_FIXTURES=1 but ${FIXTURES} unreadable: ${err instanceof Error ? err.message : err}`)\n })\n return\n }\n const res = await fetch(`${RAW}/README.md`, { method: 'HEAD' }).catch((err) => {\n throw new Error(\n `aec-bench preflight failed reaching ${RAW}: ${err instanceof Error ? err.message : err}\\n` +\n `Fix: ensure network access to raw.githubusercontent.com, or set AEC_FIXTURES=1 to run offline.`,\n )\n })\n if (!res.ok) {\n throw new Error(\n `aec-bench preflight: ${REPO} README HEAD ${res.status}. Set AEC_FIXTURES=1 to run against committed fixtures.`,\n )\n }\n },\n\n async loadTasks(opts: LoadOptions = {}) {\n if (fixturesMode) return loadFixtures(opts)\n try {\n return await loadLive(opts)\n } catch (err) {\n // A reachability failure falls back to fixtures with an explicit warn; a\n // wrong-id / seed-only error (the loader's own throw) propagates.\n if (err instanceof Error && /fetch \\d|ENOTFOUND|getaddrinfo|network/i.test(err.message)) {\n console.warn(\n `[aec-bench] live fetch failed (${err.message.slice(0, 160)}); falling back to committed fixtures at ${FIXTURES}`,\n )\n return loadFixtures(opts)\n }\n throw err\n }\n },\n\n async goldArtifact(task: BenchTask) {\n // Gold = the task's own golden_pass.md (scores reward 1.0 through the SAME\n // verify.py the real artifact takes), proving the judge end-to-end. Tasks\n // without a golden_pass.md (non-md ground truth) have no oracle artifact.\n const meta = readMeta(task)\n return meta.goldenPassMd ?? undefined\n },\n\n async judge(task: BenchTask, artifact: string): Promise<BenchScore> {\n const meta = readMeta(task)\n // verify.py fail-closes an empty/unparseable artifact to reward 0.0 itself,\n // so we pass it straight through (no pre-judging here).\n return runVerifier(meta, artifact)\n },\n }\n}\n"],"mappings":"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","names":["records"]}
|