@tangle-network/agent-bench 0.1.0 → 0.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -0
- package/HARNESS.md +302 -0
- package/README.md +39 -2
- package/dist/adapters.d.ts +15 -0
- package/dist/adapters.js +43 -0
- package/dist/adapters.js.map +1 -0
- package/dist/benchmarks/_harness.d.ts +125 -0
- package/dist/benchmarks/_harness.js +33 -0
- package/dist/benchmarks/_harness.js.map +1 -0
- package/dist/benchmarks/aec-bench.d.ts +27 -0
- package/dist/benchmarks/aec-bench.js +8 -0
- package/dist/benchmarks/aec-bench.js.map +1 -0
- package/dist/benchmarks/agentbench.d.ts +16 -0
- package/dist/benchmarks/agentbench.js +10 -0
- package/dist/benchmarks/agentbench.js.map +1 -0
- package/dist/benchmarks/appworld.d.ts +37 -0
- package/dist/benchmarks/appworld.js +14 -0
- package/dist/benchmarks/appworld.js.map +1 -0
- package/dist/benchmarks/bfcl.d.ts +18 -0
- package/dist/benchmarks/bfcl.js +10 -0
- package/dist/benchmarks/bfcl.js.map +1 -0
- package/dist/benchmarks/cad-design.d.ts +45 -0
- package/dist/benchmarks/cad-design.js +7 -0
- package/dist/benchmarks/cad-design.js.map +1 -0
- package/dist/benchmarks/cadbench.d.ts +19 -0
- package/dist/benchmarks/cadbench.js +8 -0
- package/dist/benchmarks/cadbench.js.map +1 -0
- package/dist/benchmarks/cadgenbench.d.ts +22 -0
- package/dist/benchmarks/cadgenbench.js +8 -0
- package/dist/benchmarks/cadgenbench.js.map +1 -0
- package/dist/benchmarks/commit0.d.ts +31 -0
- package/dist/benchmarks/commit0.js +10 -0
- package/dist/benchmarks/commit0.js.map +1 -0
- package/dist/benchmarks/crag.d.ts +14 -0
- package/dist/benchmarks/crag.js +9 -0
- package/dist/benchmarks/crag.js.map +1 -0
- package/dist/benchmarks/dabstep.d.ts +18 -0
- package/dist/benchmarks/dabstep.js +10 -0
- package/dist/benchmarks/dabstep.js.map +1 -0
- package/dist/benchmarks/enterpriseops-gym.d.ts +38 -0
- package/dist/benchmarks/enterpriseops-gym.js +10 -0
- package/dist/benchmarks/enterpriseops-gym.js.map +1 -0
- package/dist/benchmarks/finresearchbench.d.ts +15 -0
- package/dist/benchmarks/finresearchbench.js +8 -0
- package/dist/benchmarks/finresearchbench.js.map +1 -0
- package/dist/benchmarks/finsearchcomp.d.ts +49 -0
- package/dist/benchmarks/finsearchcomp.js +7 -0
- package/dist/benchmarks/finsearchcomp.js.map +1 -0
- package/dist/benchmarks/frames.d.ts +59 -0
- package/dist/benchmarks/frames.js +13 -0
- package/dist/benchmarks/frames.js.map +1 -0
- package/dist/benchmarks/hotpotqa.d.ts +48 -0
- package/dist/benchmarks/hotpotqa.js +15 -0
- package/dist/benchmarks/hotpotqa.js.map +1 -0
- package/dist/benchmarks/humaneval.d.ts +53 -0
- package/dist/benchmarks/humaneval.js +15 -0
- package/dist/benchmarks/humaneval.js.map +1 -0
- package/dist/benchmarks/mind2web.d.ts +41 -0
- package/dist/benchmarks/mind2web.js +9 -0
- package/dist/benchmarks/mind2web.js.map +1 -0
- package/dist/benchmarks/nomiracl.d.ts +15 -0
- package/dist/benchmarks/nomiracl.js +9 -0
- package/dist/benchmarks/nomiracl.js.map +1 -0
- package/dist/benchmarks/open-rag-bench.d.ts +14 -0
- package/dist/benchmarks/open-rag-bench.js +9 -0
- package/dist/benchmarks/open-rag-bench.js.map +1 -0
- package/dist/benchmarks/programbench.d.ts +38 -0
- package/dist/benchmarks/programbench.js +10 -0
- package/dist/benchmarks/programbench.js.map +1 -0
- package/dist/benchmarks/rag-shared.d.ts +42 -0
- package/dist/benchmarks/rag-shared.js +39 -0
- package/dist/benchmarks/rag-shared.js.map +1 -0
- package/dist/benchmarks/ragbench.d.ts +16 -0
- package/dist/benchmarks/ragbench.js +9 -0
- package/dist/benchmarks/ragbench.js.map +1 -0
- package/dist/benchmarks/simpleqa.d.ts +64 -0
- package/dist/benchmarks/simpleqa.js +11 -0
- package/dist/benchmarks/simpleqa.js.map +1 -0
- package/dist/benchmarks/swe-bench.d.ts +56 -0
- package/dist/benchmarks/swe-bench.js +14 -0
- package/dist/benchmarks/swe-bench.js.map +1 -0
- package/dist/benchmarks/t2-ragbench.d.ts +14 -0
- package/dist/benchmarks/t2-ragbench.js +9 -0
- package/dist/benchmarks/t2-ragbench.js.map +1 -0
- package/dist/benchmarks/tau-bench-shared.d.ts +26 -0
- package/dist/benchmarks/tau-bench-shared.js +10 -0
- package/dist/benchmarks/tau-bench-shared.js.map +1 -0
- package/dist/benchmarks/tau2-bench.d.ts +7 -0
- package/dist/benchmarks/tau2-bench.js +11 -0
- package/dist/benchmarks/tau2-bench.js.map +1 -0
- package/dist/benchmarks/tau3-banking.d.ts +15 -0
- package/dist/benchmarks/tau3-banking.js +9 -0
- package/dist/benchmarks/tau3-banking.js.map +1 -0
- package/dist/benchmarks/terminal-bench.d.ts +24 -0
- package/dist/benchmarks/terminal-bench.js +8 -0
- package/dist/benchmarks/terminal-bench.js.map +1 -0
- package/dist/benchmarks/toollm.d.ts +16 -0
- package/dist/benchmarks/toollm.js +10 -0
- package/dist/benchmarks/toollm.js.map +1 -0
- package/dist/benchmarks/trata-hedge.d.ts +32 -0
- package/dist/benchmarks/trata-hedge.js +7 -0
- package/dist/benchmarks/trata-hedge.js.map +1 -0
- package/dist/benchmarks/types.d.ts +107 -0
- package/dist/benchmarks/types.js +1 -0
- package/dist/benchmarks/types.js.map +1 -0
- package/dist/benchmarks/webarena-verified.d.ts +16 -0
- package/dist/benchmarks/webarena-verified.js +10 -0
- package/dist/benchmarks/webarena-verified.js.map +1 -0
- package/dist/chunk-2PVVP7GN.js +197 -0
- package/dist/chunk-2PVVP7GN.js.map +1 -0
- package/dist/chunk-2XU6OGEN.js +170 -0
- package/dist/chunk-2XU6OGEN.js.map +1 -0
- package/dist/chunk-53UPUNBZ.js +325 -0
- package/dist/chunk-53UPUNBZ.js.map +1 -0
- package/dist/chunk-5SBJCB6W.js +144 -0
- package/dist/chunk-5SBJCB6W.js.map +1 -0
- package/dist/chunk-7WSD27QQ.js +118 -0
- package/dist/chunk-7WSD27QQ.js.map +1 -0
- package/dist/chunk-C7T7WEK2.js +103 -0
- package/dist/chunk-C7T7WEK2.js.map +1 -0
- package/dist/chunk-CKUVRZ2T.js +251 -0
- package/dist/chunk-CKUVRZ2T.js.map +1 -0
- package/dist/chunk-HBSWHQNJ.js +30 -0
- package/dist/chunk-HBSWHQNJ.js.map +1 -0
- package/dist/chunk-HHXFIHXC.js +116 -0
- package/dist/chunk-HHXFIHXC.js.map +1 -0
- package/dist/chunk-IFAV6KEM.js +276 -0
- package/dist/chunk-IFAV6KEM.js.map +1 -0
- package/dist/chunk-INNOYXCP.js +387 -0
- package/dist/chunk-INNOYXCP.js.map +1 -0
- package/dist/chunk-J3KDJNX2.js +182 -0
- package/dist/chunk-J3KDJNX2.js.map +1 -0
- package/dist/chunk-JRWWGMK7.js +148 -0
- package/dist/chunk-JRWWGMK7.js.map +1 -0
- package/dist/chunk-JTHWEDEW.js +32 -0
- package/dist/chunk-JTHWEDEW.js.map +1 -0
- package/dist/chunk-KDIKRJGB.js +120 -0
- package/dist/chunk-KDIKRJGB.js.map +1 -0
- package/dist/chunk-LRRD7NAG.js +301 -0
- package/dist/chunk-LRRD7NAG.js.map +1 -0
- package/dist/chunk-ODT47UAY.js +221 -0
- package/dist/chunk-ODT47UAY.js.map +1 -0
- package/dist/chunk-PA2ZKHJC.js +230 -0
- package/dist/chunk-PA2ZKHJC.js.map +1 -0
- package/dist/chunk-PPYSEKFM.js +182 -0
- package/dist/chunk-PPYSEKFM.js.map +1 -0
- package/dist/chunk-PUIRNYI7.js +189 -0
- package/dist/chunk-PUIRNYI7.js.map +1 -0
- package/dist/chunk-R36V2VP7.js +169 -0
- package/dist/chunk-R36V2VP7.js.map +1 -0
- package/dist/chunk-R67DFVLO.js +142 -0
- package/dist/chunk-R67DFVLO.js.map +1 -0
- package/dist/chunk-SEVJPLZC.js +260 -0
- package/dist/chunk-SEVJPLZC.js.map +1 -0
- package/dist/chunk-SYDW647C.js +318 -0
- package/dist/chunk-SYDW647C.js.map +1 -0
- package/dist/chunk-TBKU5XQI.js +228 -0
- package/dist/chunk-TBKU5XQI.js.map +1 -0
- package/dist/chunk-TSWPNOYM.js +147 -0
- package/dist/chunk-TSWPNOYM.js.map +1 -0
- package/dist/chunk-UAIOHCUK.js +27 -0
- package/dist/chunk-UAIOHCUK.js.map +1 -0
- package/dist/chunk-UPAMRDX4.js +233 -0
- package/dist/chunk-UPAMRDX4.js.map +1 -0
- package/dist/chunk-VQRS7VUC.js +342 -0
- package/dist/chunk-VQRS7VUC.js.map +1 -0
- package/dist/chunk-X3BTXCJ4.js +262 -0
- package/dist/chunk-X3BTXCJ4.js.map +1 -0
- package/dist/chunk-X5YKXC6V.js +211 -0
- package/dist/chunk-X5YKXC6V.js.map +1 -0
- package/dist/chunk-Y6O2OCUO.js +130 -0
- package/dist/chunk-Y6O2OCUO.js.map +1 -0
- package/dist/chunk-YCGY7UIZ.js +208 -0
- package/dist/chunk-YCGY7UIZ.js.map +1 -0
- package/dist/chunk-Z7ML6L77.js +162 -0
- package/dist/chunk-Z7ML6L77.js.map +1 -0
- package/dist/chunk-ZEWMTR5M.js +136 -0
- package/dist/chunk-ZEWMTR5M.js.map +1 -0
- package/dist/index.d.ts +355 -0
- package/dist/index.js +1908 -0
- package/dist/index.js.map +1 -0
- package/fixtures/aec-bench.json +18 -0
- package/fixtures/agentbench-dbbench.json +22 -0
- package/fixtures/bfcl.json +45 -0
- package/fixtures/commit0.json +72 -0
- package/fixtures/crag.json +10 -0
- package/fixtures/dabstep.json +22 -0
- package/fixtures/enterpriseops-gym.json +103 -0
- package/fixtures/finresearchbench.json +21 -0
- package/fixtures/finsearchcomp.json +66 -0
- package/fixtures/frames.json +26 -0
- package/fixtures/hotpotqa.json +182 -0
- package/fixtures/nomiracl.json +26 -0
- package/fixtures/open-rag-bench.json +16 -0
- package/fixtures/pier-agent/no-model-task/environment/Dockerfile +16 -0
- package/fixtures/pier-agent/no-model-task/environment/seed/src/status.txt +1 -0
- package/fixtures/pier-agent/no-model-task/instruction.md +6 -0
- package/fixtures/pier-agent/no-model-task/pre_artifacts.sh +6 -0
- package/fixtures/pier-agent/no-model-task/task.toml +35 -0
- package/fixtures/pier-agent/no-model-task/tests/Dockerfile +17 -0
- package/fixtures/pier-agent/no-model-task/tests/seed/src/status.txt +1 -0
- package/fixtures/pier-agent/no-model-task/tests/test.sh +19 -0
- package/fixtures/programbench.json +17 -0
- package/fixtures/ragbench.json +21 -0
- package/fixtures/simpleqa.json +121 -0
- package/fixtures/t2-ragbench.json +13 -0
- package/fixtures/tau2-bench.json +16 -0
- package/fixtures/tau3-banking.json +16 -0
- package/fixtures/toollm.json +28 -0
- package/fixtures/webarena-verified.json +20 -0
- package/package.json +60 -20
- package/pier_agents/__init__.py +18 -0
- package/pier_agents/candidate_contract.py +755 -0
- package/pier_agents/process_boundary.py +321 -0
- package/pier_agents/tangle_candidate.py +907 -0
- package/pier_agents/workspace_boundary.py +368 -0
- package/scripts/appworld_driver.py +359 -0
- package/scripts/cadbench_prepare.py +22 -0
- package/scripts/cadgenbench_hard_parts.py +48 -0
- package/scripts/clbench_codebase_judge.py +73 -0
- package/scripts/commit0_judge.py +170 -0
- package/scripts/dabstep_judge.py +42 -0
- package/scripts/enterpriseops_gym_judge.py +281 -0
- package/scripts/programbench_judge.py +120 -0
- package/scripts/render-gate-chart.mjs +176 -0
- package/scripts/run-package-tests.mjs +56 -0
- package/scripts/terminate-pier-trial.mts +66 -0
- package/scripts/trata-hedge/README.md +56 -0
- package/scripts/trata-hedge/run.sh +60 -0
- package/scripts/trata-hedge/solve.py +83 -0
- package/scripts/verify-packed-consumer.mjs +235 -0
- package/scripts/verify-pier-agent.mts +715 -0
- package/scripts/verify-pier-pair.mts +74 -0
- package/scripts/verify-pier-recovery.mts +139 -0
- package/src/adapters.ts +26 -0
- package/src/benchmarks/_harness.test.mts +178 -0
- package/src/benchmarks/_harness.ts +239 -16
- package/src/benchmarks/agentbench.ts +163 -0
- package/src/benchmarks/appworld.test.mts +15 -9
- package/src/benchmarks/bfcl.ts +346 -0
- package/src/benchmarks/crag.ts +137 -0
- package/src/benchmarks/dabstep.test.mts +70 -0
- package/src/benchmarks/dabstep.ts +212 -0
- package/src/benchmarks/external-adapters.test.mts +150 -0
- package/src/benchmarks/finresearchbench.ts +269 -0
- package/src/benchmarks/humaneval.ts +20 -8
- package/src/benchmarks/nomiracl.ts +180 -0
- package/src/benchmarks/open-rag-bench.ts +153 -0
- package/src/benchmarks/rag-benchmarks.test.mts +138 -0
- package/src/benchmarks/rag-shared.ts +327 -0
- package/src/benchmarks/ragbench.ts +171 -0
- package/src/benchmarks/swe-bench.test.mts +61 -0
- package/src/benchmarks/swe-bench.ts +201 -19
- package/src/benchmarks/t2-ragbench.ts +166 -0
- package/src/benchmarks/tau-bench-shared.ts +214 -0
- package/src/benchmarks/tau2-bench.ts +30 -0
- package/src/benchmarks/tau3-banking.ts +29 -0
- package/src/benchmarks/terminal-bench.test.mts +33 -0
- package/src/benchmarks/terminal-bench.ts +23 -8
- package/src/benchmarks/toollm.ts +254 -0
- package/src/benchmarks/types.ts +42 -0
- package/src/benchmarks/webarena-verified.ts +200 -0
- package/src/commit0-prereqs.sh +0 -0
- package/src/coordination-mcp-container-reach.mts +181 -0
- package/src/decoder-live.mts +1 -1
- package/src/examples/README.md +103 -39
- package/src/examples/benchmark-matrix.mts +101 -0
- package/src/examples/lean-proof-gate.README.md +77 -0
- package/src/examples/lean-proof-gate.mts +162 -0
- package/src/examples/lean-verify.ts +95 -0
- package/src/examples/lean.Dockerfile +12 -0
- package/src/examples/math-demo.mts +9 -7
- package/src/examples/strategy-demo.mts +10 -12
- package/src/gate.ts +3 -2
- package/src/hev-eval.mts +69 -0
- package/src/hev-improve.mts +169 -0
- package/src/hev-structural.mts +688 -0
- package/src/index.ts +73 -0
- package/src/mbpp-structural.mts +662 -0
- package/src/pier-agent.test-fixtures.mts +19 -0
- package/src/pier-agent.test.mts +363 -0
- package/src/pier-agent.ts +657 -0
- package/src/pier-result-grader.mjs +30 -0
- package/src/pier-result-grader.test.mts +62 -0
- package/src/pier-result-grader.ts +108 -0
- package/src/pier-task-outcome.test.mts +117 -0
- package/src/pier-task-outcome.ts +240 -0
- package/src/pier-trial-controller.test.mts +412 -0
- package/src/pier-trial-controller.ts +858 -0
- package/src/pier-trial-supervisor.mjs +352 -0
- package/src/resolve-client.ts +25 -2
- package/src/run-benchmarks-cli.mts +72 -0
- package/src/run-benchmarks-report.ts +66 -0
- package/src/run-benchmarks.test.mts +231 -0
- package/src/run-benchmarks.ts +589 -0
- package/src/smoke-structural-rollout.mts +393 -0
- package/src/swe-bench-env.test.ts +207 -0
- package/src/swe-bench-env.ts +554 -0
- package/src/swe-jail.ts +293 -0
- package/src/swe-self-improve.mts +84 -0
- package/src/swe-structural-judge-policy.test.ts +117 -0
- package/src/swe-structural-judge-policy.ts +133 -0
- package/src/swe-structural-policy.test.ts +124 -0
- package/src/swe-structural-policy.ts +132 -0
- package/src/swe-structural-provenance.test.ts +93 -0
- package/src/swe-structural-provenance.ts +138 -0
- package/src/swe-structural.mts +1260 -0
- package/src/swe-temp.ts +14 -0
- package/src/tb-container-executor.mts +234 -0
- package/src/tb-container-executor.test.mts +99 -0
- package/src/tb-supervisor-sidecar.mts +222 -0
- package/src/trata-gepa.mts +1 -1
- package/steerers/eops-itsm-population.json +1 -0
- package/tb_agents/opencode_refine_agent.py +117 -0
- package/tb_agents/opencode_router_agent.py +406 -0
- package/tb_agents/opencode_supervisor_agent.py +239 -0
- package/tb_agents/script_agent.py +66 -0
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
import type { OutputAdapter } from '@tangle-network/agent-runtime/loops'
|
|
3
|
+
import type { BenchScore, BenchTask, LoadOptions } from './types'
|
|
4
|
+
|
|
5
|
+
export const FINAL_ANSWER_SENTINEL = 'FINAL ANSWER:'
|
|
6
|
+
|
|
7
|
+
export interface RagContext {
|
|
8
|
+
id: string
|
|
9
|
+
text: string
|
|
10
|
+
title?: string
|
|
11
|
+
source?: string
|
|
12
|
+
relevant?: boolean
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface RagAnswerScore {
|
|
16
|
+
resolved: boolean
|
|
17
|
+
score: number
|
|
18
|
+
finalAnswer: string
|
|
19
|
+
bestGold: string | null
|
|
20
|
+
exact: boolean
|
|
21
|
+
numeric: boolean
|
|
22
|
+
f1: number
|
|
23
|
+
threshold: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export const ragAnswerOutput: OutputAdapter<string> = {
|
|
27
|
+
parse(events) {
|
|
28
|
+
let text = ''
|
|
29
|
+
for (const ev of events) {
|
|
30
|
+
const d = (ev as { data?: Record<string, unknown> })?.data
|
|
31
|
+
const t = d?.finalText ?? d?.text ?? d?.result
|
|
32
|
+
if (typeof t === 'string' && t.length > 0) text = t
|
|
33
|
+
}
|
|
34
|
+
return text.trim()
|
|
35
|
+
},
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function parseFinalAnswer(artifact: string): string {
|
|
39
|
+
const lines = artifact.split(/\r?\n/)
|
|
40
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
41
|
+
const line = lines[i] ?? ''
|
|
42
|
+
const idx = line.toUpperCase().indexOf(FINAL_ANSWER_SENTINEL)
|
|
43
|
+
if (idx !== -1) return line.slice(idx + FINAL_ANSWER_SENTINEL.length).trim()
|
|
44
|
+
}
|
|
45
|
+
for (let i = lines.length - 1; i >= 0; i -= 1) {
|
|
46
|
+
const trimmed = (lines[i] ?? '').trim()
|
|
47
|
+
if (trimmed.length > 0) return trimmed
|
|
48
|
+
}
|
|
49
|
+
return ''
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export function parseCitations(artifact: string): string[] {
|
|
53
|
+
const urls = new Set<string>()
|
|
54
|
+
for (const match of artifact.matchAll(/https?:\/\/[^\s)<>"']+/g)) {
|
|
55
|
+
urls.add(match[0].replace(/[.,;]+$/, ''))
|
|
56
|
+
}
|
|
57
|
+
return [...urls]
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function normalizeAnswer(input: string): string {
|
|
61
|
+
return input
|
|
62
|
+
.toLowerCase()
|
|
63
|
+
.replace(/(\d),(?=\d{3}\b)/g, '$1')
|
|
64
|
+
.replace(/[^\p{L}\p{N}\s.-]+/gu, ' ')
|
|
65
|
+
.split(/\s+/)
|
|
66
|
+
.filter((token) => token.length > 0)
|
|
67
|
+
.filter((token) => !['a', 'an', 'the'].includes(token))
|
|
68
|
+
.join(' ')
|
|
69
|
+
.trim()
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function tokens(input: string): string[] {
|
|
73
|
+
const normalized = normalizeAnswer(input)
|
|
74
|
+
return normalized.length === 0 ? [] : normalized.split(/\s+/)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function tokenF1(candidate: string, gold: string): number {
|
|
78
|
+
const candidateTokens = tokens(candidate)
|
|
79
|
+
const goldTokens = tokens(gold)
|
|
80
|
+
if (candidateTokens.length === 0 || goldTokens.length === 0) {
|
|
81
|
+
return candidateTokens.length === 0 && goldTokens.length === 0 ? 1 : 0
|
|
82
|
+
}
|
|
83
|
+
const counts = new Map<string, number>()
|
|
84
|
+
for (const token of goldTokens) counts.set(token, (counts.get(token) ?? 0) + 1)
|
|
85
|
+
let common = 0
|
|
86
|
+
for (const token of candidateTokens) {
|
|
87
|
+
const left = counts.get(token)
|
|
88
|
+
if (left !== undefined && left > 0) {
|
|
89
|
+
common += 1
|
|
90
|
+
counts.set(token, left - 1)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (common === 0) return 0
|
|
94
|
+
const precision = common / candidateTokens.length
|
|
95
|
+
const recall = common / goldTokens.length
|
|
96
|
+
return (2 * precision * recall) / (precision + recall)
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function exactOrContains(candidate: string, gold: string): boolean {
|
|
100
|
+
const normalizedCandidate = normalizeAnswer(candidate)
|
|
101
|
+
const normalizedGold = normalizeAnswer(gold)
|
|
102
|
+
if (normalizedGold.length === 0) return false
|
|
103
|
+
if (normalizedCandidate === normalizedGold) return true
|
|
104
|
+
const escaped = normalizedGold.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')
|
|
105
|
+
return new RegExp(`(^|\\s)${escaped}(\\s|$)`).test(normalizedCandidate)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function numbers(input: string): number[] {
|
|
109
|
+
return [...input.replace(/,/g, '').matchAll(/-?\d+(?:\.\d+)?/g)]
|
|
110
|
+
.map((match) => Number(match[0]))
|
|
111
|
+
.filter(Number.isFinite)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function numericMatch(candidate: string, gold: string, relativeTolerance: number): boolean {
|
|
115
|
+
const got = numbers(candidate)
|
|
116
|
+
const want = numbers(gold)
|
|
117
|
+
if (got.length === 0 || want.length === 0) return false
|
|
118
|
+
return want.some((expected) =>
|
|
119
|
+
got.some((actual) => {
|
|
120
|
+
const tolerance = Math.max(Math.abs(expected) * relativeTolerance, relativeTolerance)
|
|
121
|
+
return Math.abs(actual - expected) <= tolerance
|
|
122
|
+
}),
|
|
123
|
+
)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export function scoreAnswerArtifact(
|
|
127
|
+
artifact: string,
|
|
128
|
+
golds: readonly string[],
|
|
129
|
+
options: { threshold?: number; numericTolerance?: number } = {},
|
|
130
|
+
): RagAnswerScore {
|
|
131
|
+
const finalAnswer = parseFinalAnswer(artifact)
|
|
132
|
+
const threshold = options.threshold ?? 0.72
|
|
133
|
+
const numericTolerance = options.numericTolerance ?? 0.01
|
|
134
|
+
let best: RagAnswerScore = {
|
|
135
|
+
resolved: false,
|
|
136
|
+
score: 0,
|
|
137
|
+
finalAnswer,
|
|
138
|
+
bestGold: null,
|
|
139
|
+
exact: false,
|
|
140
|
+
numeric: false,
|
|
141
|
+
f1: 0,
|
|
142
|
+
threshold,
|
|
143
|
+
}
|
|
144
|
+
if (finalAnswer.length === 0 || golds.length === 0) return best
|
|
145
|
+
|
|
146
|
+
for (const gold of golds) {
|
|
147
|
+
const exact = exactOrContains(finalAnswer, gold)
|
|
148
|
+
const numeric = numericMatch(finalAnswer, gold, numericTolerance)
|
|
149
|
+
const f1 = tokenF1(finalAnswer, gold)
|
|
150
|
+
const resolved = exact || numeric || f1 >= threshold
|
|
151
|
+
const score = exact || numeric ? 1 : f1
|
|
152
|
+
if (score > best.score || (resolved && !best.resolved)) {
|
|
153
|
+
best = { resolved, score, finalAnswer, bestGold: gold, exact, numeric, f1, threshold }
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return best
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function answerScoreToBenchScore(
|
|
160
|
+
score: RagAnswerScore,
|
|
161
|
+
detail: Record<string, unknown>,
|
|
162
|
+
): BenchScore {
|
|
163
|
+
return {
|
|
164
|
+
resolved: score.resolved,
|
|
165
|
+
score: score.score,
|
|
166
|
+
detail: JSON.stringify({
|
|
167
|
+
...detail,
|
|
168
|
+
finalAnswer: score.finalAnswer,
|
|
169
|
+
bestGold: score.bestGold,
|
|
170
|
+
exact: score.exact,
|
|
171
|
+
numeric: score.numeric,
|
|
172
|
+
f1: score.f1,
|
|
173
|
+
threshold: score.threshold,
|
|
174
|
+
}),
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export async function readJsonRows(path: string): Promise<unknown[]> {
|
|
179
|
+
const raw = (await readFile(path, 'utf8')).trim()
|
|
180
|
+
if (raw.length === 0) return []
|
|
181
|
+
if (raw.startsWith('[')) {
|
|
182
|
+
const parsed = JSON.parse(raw) as unknown
|
|
183
|
+
if (Array.isArray(parsed)) return parsed
|
|
184
|
+
throw new Error(`${path} must contain a JSON array when it starts with [`)
|
|
185
|
+
}
|
|
186
|
+
if (raw.startsWith('{')) {
|
|
187
|
+
try {
|
|
188
|
+
const parsed = JSON.parse(raw) as unknown
|
|
189
|
+
if (isObject(parsed)) {
|
|
190
|
+
for (const key of ['rows', 'data', 'examples', 'items']) {
|
|
191
|
+
const value = parsed[key]
|
|
192
|
+
if (Array.isArray(value)) return value
|
|
193
|
+
}
|
|
194
|
+
return [parsed]
|
|
195
|
+
}
|
|
196
|
+
throw new Error(`${path} must contain a JSON object, JSON array, JSONL rows, or an object with rows/data/examples/items`)
|
|
197
|
+
} catch (err) {
|
|
198
|
+
if (!raw.includes('\n')) throw err
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return raw
|
|
202
|
+
.split(/\r?\n/)
|
|
203
|
+
.map((line) => line.trim())
|
|
204
|
+
.filter((line) => line.length > 0)
|
|
205
|
+
.map((line) => JSON.parse(line) as unknown)
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
export function selectTasks(tasks: BenchTask[], opts: LoadOptions, label: string): BenchTask[] {
|
|
209
|
+
let selected = tasks
|
|
210
|
+
if (opts.split) selected = selected.filter((task) => task.split === opts.split)
|
|
211
|
+
if (opts.ids) {
|
|
212
|
+
const ids = new Set(opts.ids)
|
|
213
|
+
selected = selected.filter((task) => ids.has(task.id))
|
|
214
|
+
} else if (opts.limit !== undefined) {
|
|
215
|
+
selected = selected.slice(0, opts.limit)
|
|
216
|
+
}
|
|
217
|
+
if (selected.length === 0) throw new Error(`${label}: no tasks matched ${JSON.stringify(opts)}`)
|
|
218
|
+
return selected
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function stringFrom(value: unknown): string | undefined {
|
|
222
|
+
return typeof value === 'string' && value.trim().length > 0 ? value.trim() : undefined
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
export function stringArrayFrom(value: unknown): string[] {
|
|
226
|
+
if (typeof value === 'string' && value.trim().length > 0) return [value.trim()]
|
|
227
|
+
if (!Array.isArray(value)) return []
|
|
228
|
+
return value.flatMap((entry) => {
|
|
229
|
+
if (typeof entry === 'string' && entry.trim().length > 0) return [entry.trim()]
|
|
230
|
+
if (isObject(entry)) {
|
|
231
|
+
const text = stringFrom(entry.answer) ?? stringFrom(entry.value) ?? stringFrom(entry.text)
|
|
232
|
+
return text ? [text] : []
|
|
233
|
+
}
|
|
234
|
+
return []
|
|
235
|
+
})
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
export function firstString(row: Record<string, unknown>, keys: readonly string[]): string {
|
|
239
|
+
for (const key of keys) {
|
|
240
|
+
const value = stringFrom(row[key])
|
|
241
|
+
if (value) return value
|
|
242
|
+
}
|
|
243
|
+
return ''
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function allStrings(row: Record<string, unknown>, keys: readonly string[]): string[] {
|
|
247
|
+
const out: string[] = []
|
|
248
|
+
for (const key of keys) out.push(...stringArrayFrom(row[key]))
|
|
249
|
+
return [...new Set(out)]
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
export function contextsFrom(value: unknown): RagContext[] {
|
|
253
|
+
if (typeof value === 'string' && value.trim().length > 0) {
|
|
254
|
+
return [{ id: 'ctx-1', text: value.trim() }]
|
|
255
|
+
}
|
|
256
|
+
if (!Array.isArray(value)) return []
|
|
257
|
+
return value.flatMap((entry, index): RagContext[] => {
|
|
258
|
+
if (typeof entry === 'string' && entry.trim().length > 0) {
|
|
259
|
+
return [{ id: `ctx-${index + 1}`, text: entry.trim() }]
|
|
260
|
+
}
|
|
261
|
+
if (Array.isArray(entry)) {
|
|
262
|
+
const [first, second] = entry
|
|
263
|
+
if (typeof first === 'string' && typeof second === 'string') {
|
|
264
|
+
return [{ id: first, text: second.trim() }]
|
|
265
|
+
}
|
|
266
|
+
return entry.flatMap((nested, nestedIndex) =>
|
|
267
|
+
contextsFrom([nested]).map((ctx) => ({
|
|
268
|
+
...ctx,
|
|
269
|
+
id: ctx.id.startsWith('ctx-') ? `ctx-${index + 1}-${nestedIndex + 1}` : ctx.id,
|
|
270
|
+
})),
|
|
271
|
+
)
|
|
272
|
+
}
|
|
273
|
+
if (!isObject(entry)) return []
|
|
274
|
+
const text =
|
|
275
|
+
stringFrom(entry.text) ??
|
|
276
|
+
stringFrom(entry.context) ??
|
|
277
|
+
stringFrom(entry.content) ??
|
|
278
|
+
stringFrom(entry.passage) ??
|
|
279
|
+
stringFrom(entry.document) ??
|
|
280
|
+
stringFrom(entry.page_content) ??
|
|
281
|
+
stringFrom(entry.chunk)
|
|
282
|
+
if (!text) return []
|
|
283
|
+
const id =
|
|
284
|
+
stringFrom(entry.id) ??
|
|
285
|
+
stringFrom(entry.docid) ??
|
|
286
|
+
stringFrom(entry.doc_id) ??
|
|
287
|
+
stringFrom(entry.document_id) ??
|
|
288
|
+
`ctx-${index + 1}`
|
|
289
|
+
const relevantRaw = entry.relevant ?? entry.is_relevant ?? entry.label ?? entry.relevance
|
|
290
|
+
const relevant =
|
|
291
|
+
typeof relevantRaw === 'boolean'
|
|
292
|
+
? relevantRaw
|
|
293
|
+
: typeof relevantRaw === 'number'
|
|
294
|
+
? relevantRaw > 0
|
|
295
|
+
: undefined
|
|
296
|
+
return [
|
|
297
|
+
{
|
|
298
|
+
id,
|
|
299
|
+
text,
|
|
300
|
+
...(stringFrom(entry.title) ? { title: stringFrom(entry.title) } : {}),
|
|
301
|
+
...(stringFrom(entry.source) ?? stringFrom(entry.url)
|
|
302
|
+
? { source: stringFrom(entry.source) ?? stringFrom(entry.url) }
|
|
303
|
+
: {}),
|
|
304
|
+
...(relevant !== undefined ? { relevant } : {}),
|
|
305
|
+
},
|
|
306
|
+
]
|
|
307
|
+
})
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function contextBlock(contexts: readonly RagContext[]): string {
|
|
311
|
+
if (contexts.length === 0) return ''
|
|
312
|
+
return contexts
|
|
313
|
+
.map((ctx, index) =>
|
|
314
|
+
[
|
|
315
|
+
`[${index + 1}] ${ctx.title ?? ctx.id}`,
|
|
316
|
+
ctx.source ? `Source: ${ctx.source}` : undefined,
|
|
317
|
+
ctx.text,
|
|
318
|
+
]
|
|
319
|
+
.filter(Boolean)
|
|
320
|
+
.join('\n'),
|
|
321
|
+
)
|
|
322
|
+
.join('\n\n')
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
export function isObject(value: unknown): value is Record<string, unknown> {
|
|
326
|
+
return Boolean(value) && typeof value === 'object' && !Array.isArray(value)
|
|
327
|
+
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RAGBench-compatible adapter.
|
|
3
|
+
*
|
|
4
|
+
* Live mode expects a local JSON/JSONL export from rungalileo/ragbench or a
|
|
5
|
+
* compatible table. Rows must carry a query and at least one reference answer.
|
|
6
|
+
* Contexts, TRACe labels, and source metadata are preserved in task metadata
|
|
7
|
+
* for diagnostics; the deterministic judge scores the worker's final answer
|
|
8
|
+
* against the reference answer(s).
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFile } from 'node:fs/promises'
|
|
12
|
+
import { join } from 'node:path'
|
|
13
|
+
import { benchRoot } from './_harness'
|
|
14
|
+
import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
|
|
15
|
+
import {
|
|
16
|
+
FINAL_ANSWER_SENTINEL,
|
|
17
|
+
allStrings,
|
|
18
|
+
answerScoreToBenchScore,
|
|
19
|
+
contextBlock,
|
|
20
|
+
contextsFrom,
|
|
21
|
+
firstString,
|
|
22
|
+
isObject,
|
|
23
|
+
ragAnswerOutput,
|
|
24
|
+
readJsonRows,
|
|
25
|
+
scoreAnswerArtifact,
|
|
26
|
+
selectTasks,
|
|
27
|
+
stringFrom,
|
|
28
|
+
type RagContext,
|
|
29
|
+
} from './rag-shared'
|
|
30
|
+
|
|
31
|
+
const FIXTURES = join(benchRoot, 'fixtures', 'ragbench.json')
|
|
32
|
+
|
|
33
|
+
interface RagBenchMeta {
|
|
34
|
+
benchmark: 'ragbench'
|
|
35
|
+
query: string
|
|
36
|
+
goldAnswers: string[]
|
|
37
|
+
contexts: RagContext[]
|
|
38
|
+
dataset?: string
|
|
39
|
+
traceLabels: Record<string, unknown>
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const dataFile = (): string | undefined => process.env.RAGBENCH_DATA_FILE
|
|
43
|
+
|
|
44
|
+
function rowToTask(raw: unknown, index: number): BenchTask {
|
|
45
|
+
if (!isObject(raw)) throw new Error(`RAGBench row ${index} must be an object`)
|
|
46
|
+
const query = firstString(raw, ['question', 'query', 'user_input', 'prompt'])
|
|
47
|
+
const goldAnswers = allStrings(raw, [
|
|
48
|
+
'response',
|
|
49
|
+
'responses',
|
|
50
|
+
'model_response',
|
|
51
|
+
'generated_response',
|
|
52
|
+
'reference',
|
|
53
|
+
'references',
|
|
54
|
+
'reference_answer',
|
|
55
|
+
'reference_answers',
|
|
56
|
+
'answer',
|
|
57
|
+
'answers',
|
|
58
|
+
'gold',
|
|
59
|
+
'gold_answer',
|
|
60
|
+
'ground_truth',
|
|
61
|
+
'expected_answer',
|
|
62
|
+
])
|
|
63
|
+
if (!query) throw new Error(`RAGBench row ${index} missing question/query`)
|
|
64
|
+
if (goldAnswers.length === 0) throw new Error(`RAGBench row ${index} missing reference answer`)
|
|
65
|
+
const contexts =
|
|
66
|
+
contextsFrom(raw.contexts).length > 0
|
|
67
|
+
? contextsFrom(raw.contexts)
|
|
68
|
+
: contextsFrom(raw.retrieved_contexts).length > 0
|
|
69
|
+
? contextsFrom(raw.retrieved_contexts)
|
|
70
|
+
: contextsFrom(raw.documents)
|
|
71
|
+
const traceLabels: Record<string, unknown> = {}
|
|
72
|
+
for (const key of [
|
|
73
|
+
'adherence',
|
|
74
|
+
'completeness',
|
|
75
|
+
'relevance',
|
|
76
|
+
'utilization',
|
|
77
|
+
'all_relevant_sentence_keys',
|
|
78
|
+
'all_utilized_sentence_keys',
|
|
79
|
+
]) {
|
|
80
|
+
if (raw[key] !== undefined) traceLabels[key] = raw[key]
|
|
81
|
+
}
|
|
82
|
+
const dataset = stringFrom(raw.dataset) ?? stringFrom(raw.source_dataset)
|
|
83
|
+
const id = stringFrom(raw.id) ?? stringFrom(raw.example_id) ?? `ragbench-${index}`
|
|
84
|
+
const meta: RagBenchMeta = {
|
|
85
|
+
benchmark: 'ragbench',
|
|
86
|
+
query,
|
|
87
|
+
goldAnswers,
|
|
88
|
+
contexts,
|
|
89
|
+
...(dataset ? { dataset } : {}),
|
|
90
|
+
traceLabels,
|
|
91
|
+
}
|
|
92
|
+
return {
|
|
93
|
+
id,
|
|
94
|
+
split: stringFrom(raw.split) ?? dataset ?? 'ragbench',
|
|
95
|
+
prompt: [
|
|
96
|
+
'Answer this RAGBench question using the supplied retrieved context.',
|
|
97
|
+
'End with a single final line: `FINAL ANSWER: <answer>`.',
|
|
98
|
+
'',
|
|
99
|
+
`Question: ${query}`,
|
|
100
|
+
contexts.length > 0 ? `\nRetrieved context:\n${contextBlock(contexts)}` : undefined,
|
|
101
|
+
]
|
|
102
|
+
.filter(Boolean)
|
|
103
|
+
.join('\n'),
|
|
104
|
+
metadata: meta as unknown as Record<string, unknown>,
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function readMeta(task: BenchTask): RagBenchMeta {
|
|
109
|
+
const md = task.metadata
|
|
110
|
+
if (!md || !Array.isArray(md.goldAnswers)) {
|
|
111
|
+
throw new Error(`RAGBench task ${task.id} missing metadata — loadTasks did not populate it`)
|
|
112
|
+
}
|
|
113
|
+
return md as unknown as RagBenchMeta
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function loadRows(path: string): Promise<unknown[]> {
|
|
117
|
+
const rows = await readJsonRows(path)
|
|
118
|
+
if (rows.length === 0) throw new Error(`RAGBench: no rows in ${path}`)
|
|
119
|
+
return rows
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
async function loadFixtures(opts: LoadOptions): Promise<BenchTask[]> {
|
|
123
|
+
const rows = JSON.parse(await readFile(FIXTURES, 'utf8')) as unknown[]
|
|
124
|
+
console.warn(`[ragbench] RAGBENCH_FIXTURES=1 — loading ${rows.length} adapter fixtures`)
|
|
125
|
+
return selectTasks(rows.map(rowToTask), opts, 'RAGBench')
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function createRagBenchAdapter(): BenchmarkAdapter {
|
|
129
|
+
const fixturesMode = process.env.RAGBENCH_FIXTURES === '1'
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
name: 'ragbench',
|
|
133
|
+
output: ragAnswerOutput,
|
|
134
|
+
|
|
135
|
+
async preflight() {
|
|
136
|
+
if (fixturesMode) {
|
|
137
|
+
await readFile(FIXTURES, 'utf8')
|
|
138
|
+
return
|
|
139
|
+
}
|
|
140
|
+
const path = dataFile()
|
|
141
|
+
if (!path) {
|
|
142
|
+
throw new Error(
|
|
143
|
+
'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.',
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
await loadRows(path)
|
|
147
|
+
},
|
|
148
|
+
|
|
149
|
+
async loadTasks(opts: LoadOptions = {}) {
|
|
150
|
+
if (fixturesMode) return loadFixtures(opts)
|
|
151
|
+
const path = dataFile()
|
|
152
|
+
if (!path) throw new Error('RAGBENCH_DATA_FILE is required to load RAGBench tasks')
|
|
153
|
+
return selectTasks((await loadRows(path)).map(rowToTask), opts, 'RAGBench')
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
async goldArtifact(task: BenchTask) {
|
|
157
|
+
return `${FINAL_ANSWER_SENTINEL} ${readMeta(task).goldAnswers[0] ?? ''}`
|
|
158
|
+
},
|
|
159
|
+
|
|
160
|
+
async judge(task: BenchTask, artifact: string): Promise<BenchScore> {
|
|
161
|
+
const meta = readMeta(task)
|
|
162
|
+
const score = scoreAnswerArtifact(artifact, meta.goldAnswers)
|
|
163
|
+
return answerScoreToBenchScore(score, {
|
|
164
|
+
benchmark: meta.benchmark,
|
|
165
|
+
dataset: meta.dataset ?? null,
|
|
166
|
+
traceLabels: meta.traceLabels,
|
|
167
|
+
contextCount: meta.contexts.length,
|
|
168
|
+
})
|
|
169
|
+
},
|
|
170
|
+
}
|
|
171
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import test from 'node:test'
|
|
3
|
+
import { createSweBenchAdapter, scoreSweReport, sweEvaluationArgv } from './swe-bench'
|
|
4
|
+
|
|
5
|
+
const taskId = 'django__django-12345'
|
|
6
|
+
|
|
7
|
+
test('scoreSweReport preserves official resolved, unresolved, and empty-patch outcomes', () => {
|
|
8
|
+
assert.equal(
|
|
9
|
+
scoreSweReport(taskId, { submitted_ids: [taskId], completed_ids: [taskId], resolved_ids: [taskId] }).score,
|
|
10
|
+
1,
|
|
11
|
+
)
|
|
12
|
+
assert.equal(
|
|
13
|
+
scoreSweReport(taskId, { submitted_ids: [taskId], completed_ids: [taskId], unresolved_ids: [taskId] }).score,
|
|
14
|
+
0,
|
|
15
|
+
)
|
|
16
|
+
assert.equal(scoreSweReport(taskId, { submitted_ids: [taskId], empty_patch_ids: [taskId] }).score, 0)
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
test('scoreSweReport rejects evaluator failures instead of scoring them as agent failures', () => {
|
|
20
|
+
assert.throws(() => scoreSweReport(taskId, { submitted_ids: [taskId], error_ids: [taskId] }), /evaluator failed/)
|
|
21
|
+
assert.throws(() => scoreSweReport(taskId, { submitted_ids: [taskId], incomplete_ids: [taskId] }), /evaluator failed/)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('scoreSweReport rejects missing, ambiguous, malformed, and mismatched outcomes', () => {
|
|
25
|
+
assert.throws(() => scoreSweReport(taskId, { submitted_ids: [taskId] }), /no unique outcome/)
|
|
26
|
+
assert.throws(
|
|
27
|
+
() => scoreSweReport(taskId, { resolved_ids: [taskId], unresolved_ids: [taskId] }),
|
|
28
|
+
/no unique outcome/,
|
|
29
|
+
)
|
|
30
|
+
assert.throws(() => scoreSweReport(taskId, { resolved_ids: taskId }), /malformed resolved_ids/)
|
|
31
|
+
assert.throws(() => scoreSweReport(taskId, { resolved_ids: ['other__repo-1'] }), /identity mismatch/)
|
|
32
|
+
assert.throws(() => scoreSweReport(taskId, { resolved_ids: [taskId] }), /lacks a completed evaluation/)
|
|
33
|
+
assert.throws(
|
|
34
|
+
() => scoreSweReport(taskId, { submitted_ids: [taskId, 'other__repo-1'], empty_patch_ids: [taskId] }),
|
|
35
|
+
/identity mismatch/,
|
|
36
|
+
)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
test('createSweBenchAdapter accepts only positive integer evaluation timeouts', () => {
|
|
40
|
+
assert.doesNotThrow(() => createSweBenchAdapter({ timeoutMs: 1_200_000 }))
|
|
41
|
+
assert.throws(() => createSweBenchAdapter({ timeoutMs: 0 }), /positive integer/)
|
|
42
|
+
assert.throws(() => createSweBenchAdapter({ timeoutMs: 1.5 }), /positive integer/)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('SWE evaluation command preserves the requested instance image', () => {
|
|
46
|
+
const argv = sweEvaluationArgv({
|
|
47
|
+
predictionsPath: '/tmp/preds.json',
|
|
48
|
+
runId: 'r364',
|
|
49
|
+
instanceId: taskId,
|
|
50
|
+
cacheLevel: 'instance',
|
|
51
|
+
namespace: 'none',
|
|
52
|
+
})
|
|
53
|
+
const cacheIndex = argv.indexOf('--cache_level')
|
|
54
|
+
const namespaceIndex = argv.indexOf('--namespace')
|
|
55
|
+
assert.equal(argv[cacheIndex + 1], 'instance')
|
|
56
|
+
assert.equal(argv[namespaceIndex + 1], 'none')
|
|
57
|
+
assert.throws(
|
|
58
|
+
() => createSweBenchAdapter({ cacheLevel: 'invalid' as 'instance' }),
|
|
59
|
+
/invalid cacheLevel/,
|
|
60
|
+
)
|
|
61
|
+
})
|