@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.
Files changed (200) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/adapters.d.ts +4 -11
  3. package/dist/adapters.js +78 -41
  4. package/dist/adapters.js.map +1 -1
  5. package/dist/benchmarks/_harness.d.ts +51 -66
  6. package/dist/benchmarks/_harness.js +329 -31
  7. package/dist/benchmarks/_harness.js.map +1 -1
  8. package/dist/benchmarks/aec-bench.d.ts +4 -25
  9. package/dist/benchmarks/aec-bench.js +242 -7
  10. package/dist/benchmarks/aec-bench.js.map +1 -1
  11. package/dist/benchmarks/agentbench.d.ts +5 -13
  12. package/dist/benchmarks/agentbench.js +114 -9
  13. package/dist/benchmarks/agentbench.js.map +1 -1
  14. package/dist/benchmarks/appworld.d.ts +9 -29
  15. package/dist/benchmarks/appworld.js +317 -12
  16. package/dist/benchmarks/appworld.js.map +1 -1
  17. package/dist/benchmarks/bfcl.d.ts +5 -15
  18. package/dist/benchmarks/bfcl.js +264 -9
  19. package/dist/benchmarks/bfcl.js.map +1 -1
  20. package/dist/benchmarks/cad-design.d.ts +16 -41
  21. package/dist/benchmarks/cad-design.js +512 -6
  22. package/dist/benchmarks/cad-design.js.map +1 -1
  23. package/dist/benchmarks/cadbench.d.ts +4 -17
  24. package/dist/benchmarks/cadbench.js +2 -8
  25. package/dist/benchmarks/cadgenbench.d.ts +4 -20
  26. package/dist/benchmarks/cadgenbench.js +2 -8
  27. package/dist/benchmarks/commit0.d.ts +5 -27
  28. package/dist/benchmarks/commit0.js +187 -9
  29. package/dist/benchmarks/commit0.js.map +1 -1
  30. package/dist/benchmarks/crag.d.ts +4 -12
  31. package/dist/benchmarks/crag.js +110 -8
  32. package/dist/benchmarks/crag.js.map +1 -1
  33. package/dist/benchmarks/dabstep.d.ts +5 -15
  34. package/dist/benchmarks/dabstep.js +177 -9
  35. package/dist/benchmarks/dabstep.js.map +1 -1
  36. package/dist/benchmarks/enterpriseops-gym.d.ts +5 -34
  37. package/dist/benchmarks/enterpriseops-gym.js +236 -9
  38. package/dist/benchmarks/enterpriseops-gym.js.map +1 -1
  39. package/dist/benchmarks/finresearchbench.d.ts +4 -13
  40. package/dist/benchmarks/finresearchbench.js +218 -7
  41. package/dist/benchmarks/finresearchbench.js.map +1 -1
  42. package/dist/benchmarks/finsearchcomp.d.ts +8 -39
  43. package/dist/benchmarks/finsearchcomp.js +267 -6
  44. package/dist/benchmarks/finsearchcomp.js.map +1 -1
  45. package/dist/benchmarks/frames.d.ts +15 -37
  46. package/dist/benchmarks/frames.js +408 -11
  47. package/dist/benchmarks/frames.js.map +1 -1
  48. package/dist/benchmarks/hotpotqa.d.ts +4 -24
  49. package/dist/benchmarks/hotpotqa.js +250 -14
  50. package/dist/benchmarks/hotpotqa.js.map +1 -1
  51. package/dist/benchmarks/humaneval.d.ts +19 -37
  52. package/dist/benchmarks/humaneval.js +279 -16
  53. package/dist/benchmarks/humaneval.js.map +1 -1
  54. package/dist/benchmarks/mind2web.d.ts +7 -34
  55. package/dist/benchmarks/mind2web.js +257 -8
  56. package/dist/benchmarks/mind2web.js.map +1 -1
  57. package/dist/benchmarks/nomiracl.d.ts +4 -13
  58. package/dist/benchmarks/nomiracl.js +146 -8
  59. package/dist/benchmarks/nomiracl.js.map +1 -1
  60. package/dist/benchmarks/open-rag-bench.d.ts +4 -12
  61. package/dist/benchmarks/open-rag-bench.js +110 -8
  62. package/dist/benchmarks/open-rag-bench.js.map +1 -1
  63. package/dist/benchmarks/programbench.d.ts +5 -29
  64. package/dist/benchmarks/programbench.js +161 -9
  65. package/dist/benchmarks/programbench.js.map +1 -1
  66. package/dist/benchmarks/rag-shared.d.ts +21 -20
  67. package/dist/benchmarks/rag-shared.js +245 -38
  68. package/dist/benchmarks/rag-shared.js.map +1 -1
  69. package/dist/benchmarks/ragbench.d.ts +4 -14
  70. package/dist/benchmarks/ragbench.js +127 -8
  71. package/dist/benchmarks/ragbench.js.map +1 -1
  72. package/dist/benchmarks/simpleqa.d.ts +17 -44
  73. package/dist/benchmarks/simpleqa.js +293 -10
  74. package/dist/benchmarks/simpleqa.js.map +1 -1
  75. package/dist/benchmarks/swe-bench.d.ts +23 -36
  76. package/dist/benchmarks/swe-bench.js +234 -13
  77. package/dist/benchmarks/swe-bench.js.map +1 -1
  78. package/dist/benchmarks/t2-ragbench.d.ts +4 -12
  79. package/dist/benchmarks/t2-ragbench.js +118 -8
  80. package/dist/benchmarks/t2-ragbench.js.map +1 -1
  81. package/dist/benchmarks/tau-bench-shared.d.ts +14 -22
  82. package/dist/benchmarks/tau-bench-shared.js +169 -9
  83. package/dist/benchmarks/tau-bench-shared.js.map +1 -1
  84. package/dist/benchmarks/tau2-bench.d.ts +5 -5
  85. package/dist/benchmarks/tau2-bench.js +28 -10
  86. package/dist/benchmarks/tau2-bench.js.map +1 -1
  87. package/dist/benchmarks/tau3-banking.d.ts +4 -13
  88. package/dist/benchmarks/tau3-banking.js +28 -8
  89. package/dist/benchmarks/tau3-banking.js.map +1 -1
  90. package/dist/benchmarks/terminal-bench.d.ts +4 -22
  91. package/dist/benchmarks/terminal-bench.js +140 -7
  92. package/dist/benchmarks/terminal-bench.js.map +1 -1
  93. package/dist/benchmarks/toollm.d.ts +5 -13
  94. package/dist/benchmarks/toollm.js +184 -9
  95. package/dist/benchmarks/toollm.js.map +1 -1
  96. package/dist/benchmarks/trata-hedge.d.ts +4 -30
  97. package/dist/benchmarks/trata-hedge.js +336 -6
  98. package/dist/benchmarks/trata-hedge.js.map +1 -1
  99. package/dist/benchmarks/types.d.ts +85 -94
  100. package/dist/benchmarks/types.js +1 -1
  101. package/dist/benchmarks/webarena-verified.d.ts +5 -13
  102. package/dist/benchmarks/webarena-verified.js +152 -9
  103. package/dist/benchmarks/webarena-verified.js.map +1 -1
  104. package/dist/cadbench-DpQWZHp4.js +285 -0
  105. package/dist/cadbench-DpQWZHp4.js.map +1 -0
  106. package/dist/cadgenbench-DRhczfsG.js +151 -0
  107. package/dist/cadgenbench-DRhczfsG.js.map +1 -0
  108. package/dist/index.d.ts +245 -293
  109. package/dist/index.js +1669 -1791
  110. package/dist/index.js.map +1 -1
  111. package/package.json +17 -14
  112. package/pier_agents/candidate_contract.py +238 -24
  113. package/pier_agents/tangle_candidate.py +75 -5
  114. package/scripts/verify-packed-consumer.mjs +84 -17
  115. package/scripts/verify-pier-agent.mts +6 -4
  116. package/src/benchmarks/_harness.test.mts +16 -1
  117. package/src/benchmarks/_harness.ts +9 -2
  118. package/src/benchmarks/terminal-bench.ts +2 -1
  119. package/src/corpus.test.mts +13 -0
  120. package/src/corpus.ts +4 -0
  121. package/src/profile-coordinates.ts +2 -2
  122. package/src/rollout-ledger/backfill-swe-arena.mts +5 -1
  123. package/src/rollout-ledger/settle-capture.mts +7 -1
  124. package/src/search-bench/profiles.ts +1 -1
  125. package/src/skill-sandbox-smoke.mts +2 -1
  126. package/src/swe-arena/gepa-seat.mts +1 -1
  127. package/src/swe-arena/ledger-orphans.test.mts +36 -34
  128. package/dist/benchmarks/cadbench.js.map +0 -1
  129. package/dist/benchmarks/cadgenbench.js.map +0 -1
  130. package/dist/benchmarks/types.js.map +0 -1
  131. package/dist/chunk-3U5TXJZS.js +0 -251
  132. package/dist/chunk-3U5TXJZS.js.map +0 -1
  133. package/dist/chunk-53UPUNBZ.js +0 -325
  134. package/dist/chunk-53UPUNBZ.js.map +0 -1
  135. package/dist/chunk-5H5XV76F.js +0 -240
  136. package/dist/chunk-5H5XV76F.js.map +0 -1
  137. package/dist/chunk-7GRVHU22.js +0 -208
  138. package/dist/chunk-7GRVHU22.js.map +0 -1
  139. package/dist/chunk-C7T7WEK2.js +0 -103
  140. package/dist/chunk-C7T7WEK2.js.map +0 -1
  141. package/dist/chunk-HWST3SED.js +0 -162
  142. package/dist/chunk-HWST3SED.js.map +0 -1
  143. package/dist/chunk-IA2FBTWC.js +0 -318
  144. package/dist/chunk-IA2FBTWC.js.map +0 -1
  145. package/dist/chunk-IFVINJ4B.js +0 -142
  146. package/dist/chunk-IFVINJ4B.js.map +0 -1
  147. package/dist/chunk-INNOYXCP.js +0 -387
  148. package/dist/chunk-INNOYXCP.js.map +0 -1
  149. package/dist/chunk-IZ5M6OAC.js +0 -169
  150. package/dist/chunk-IZ5M6OAC.js.map +0 -1
  151. package/dist/chunk-JTHWEDEW.js +0 -32
  152. package/dist/chunk-JTHWEDEW.js.map +0 -1
  153. package/dist/chunk-K3BQGZCT.js +0 -221
  154. package/dist/chunk-K3BQGZCT.js.map +0 -1
  155. package/dist/chunk-KP5KD6EN.js +0 -276
  156. package/dist/chunk-KP5KD6EN.js.map +0 -1
  157. package/dist/chunk-MQMRLGOG.js +0 -136
  158. package/dist/chunk-MQMRLGOG.js.map +0 -1
  159. package/dist/chunk-NQG5XDSB.js +0 -147
  160. package/dist/chunk-NQG5XDSB.js.map +0 -1
  161. package/dist/chunk-PA2ZKHJC.js +0 -230
  162. package/dist/chunk-PA2ZKHJC.js.map +0 -1
  163. package/dist/chunk-PB64GYIG.js +0 -118
  164. package/dist/chunk-PB64GYIG.js.map +0 -1
  165. package/dist/chunk-PUIRNYI7.js +0 -189
  166. package/dist/chunk-PUIRNYI7.js.map +0 -1
  167. package/dist/chunk-RCYQEFNX.js +0 -30
  168. package/dist/chunk-RCYQEFNX.js.map +0 -1
  169. package/dist/chunk-RH5F53JT.js +0 -182
  170. package/dist/chunk-RH5F53JT.js.map +0 -1
  171. package/dist/chunk-SEVJPLZC.js +0 -260
  172. package/dist/chunk-SEVJPLZC.js.map +0 -1
  173. package/dist/chunk-SFLA7OH3.js +0 -27
  174. package/dist/chunk-SFLA7OH3.js.map +0 -1
  175. package/dist/chunk-SHM6MRRF.js +0 -130
  176. package/dist/chunk-SHM6MRRF.js.map +0 -1
  177. package/dist/chunk-SHYIRB7I.js +0 -120
  178. package/dist/chunk-SHYIRB7I.js.map +0 -1
  179. package/dist/chunk-SVR2LKYI.js +0 -116
  180. package/dist/chunk-SVR2LKYI.js.map +0 -1
  181. package/dist/chunk-TBKU5XQI.js +0 -228
  182. package/dist/chunk-TBKU5XQI.js.map +0 -1
  183. package/dist/chunk-UPAMRDX4.js +0 -233
  184. package/dist/chunk-UPAMRDX4.js.map +0 -1
  185. package/dist/chunk-V7AEBY6U.js +0 -144
  186. package/dist/chunk-V7AEBY6U.js.map +0 -1
  187. package/dist/chunk-VQRS7VUC.js +0 -342
  188. package/dist/chunk-VQRS7VUC.js.map +0 -1
  189. package/dist/chunk-WSKWVEQB.js +0 -317
  190. package/dist/chunk-WSKWVEQB.js.map +0 -1
  191. package/dist/chunk-X3BTXCJ4.js +0 -262
  192. package/dist/chunk-X3BTXCJ4.js.map +0 -1
  193. package/dist/chunk-XKEFIFIC.js +0 -197
  194. package/dist/chunk-XKEFIFIC.js.map +0 -1
  195. package/dist/chunk-XYA4XSNU.js +0 -148
  196. package/dist/chunk-XYA4XSNU.js.map +0 -1
  197. package/dist/chunk-YSMEKBTD.js +0 -211
  198. package/dist/chunk-YSMEKBTD.js.map +0 -1
  199. package/dist/chunk-Z4TZ76N7.js +0 -170
  200. package/dist/chunk-Z4TZ76N7.js.map +0 -1
@@ -52,11 +52,58 @@ async function resolveRuntimePackage(packDir) {
52
52
 
53
53
  try {
54
54
  const packDir = path.join(scratch, 'pack')
55
+ const unpackDir = path.join(scratch, 'unpack')
55
56
  const runtimePackDir = path.join(scratch, 'runtime-pack')
56
57
  const consumerDir = path.join(scratch, 'consumer')
58
+ const terminalBenchVenv = path.join(scratch, 'terminal-bench-venv')
59
+ const terminalBenchBinDir = path.join(terminalBenchVenv, 'bin')
57
60
  await mkdir(packDir)
61
+ await mkdir(unpackDir)
58
62
  await mkdir(runtimePackDir)
59
63
  await mkdir(consumerDir)
64
+ await mkdir(terminalBenchBinDir, { recursive: true })
65
+ await writeFile(path.join(terminalBenchVenv, 'package.json'), '{"type":"module"}\n')
66
+ await writeFile(
67
+ path.join(terminalBenchBinDir, 'python'),
68
+ String.raw`#!/usr/bin/env node
69
+ const rows = [{
70
+ id: 'installed-absolute-venv',
71
+ instruction: 'prove the installed path',
72
+ task_dir: '/tmp/terminal-bench-task',
73
+ solution: 'echo ok\n',
74
+ }]
75
+ process.stdout.write(JSON.stringify(rows) + '\n')
76
+ `,
77
+ { mode: 0o755 },
78
+ )
79
+ await writeFile(
80
+ path.join(terminalBenchBinDir, 'tb'),
81
+ String.raw`#!/usr/bin/env node
82
+ import { mkdirSync, writeFileSync } from 'node:fs'
83
+ import { join } from 'node:path'
84
+
85
+ const args = process.argv.slice(2)
86
+ function value(flag) {
87
+ const index = args.indexOf(flag)
88
+ if (index === -1 || index + 1 >= args.length) throw new Error('missing ' + flag)
89
+ return args[index + 1]
90
+ }
91
+
92
+ const outputPath = value('--output-path')
93
+ const runId = value('--run-id')
94
+ const taskId = value('-t')
95
+ const reportDir = join(outputPath, runId)
96
+ mkdirSync(reportDir, { recursive: true })
97
+ writeFileSync(
98
+ join(reportDir, 'results.json'),
99
+ JSON.stringify({
100
+ resolved_ids: [taskId],
101
+ results: [{ task_id: taskId, is_resolved: true, parser_results: { installedVenv: true } }],
102
+ }),
103
+ )
104
+ `,
105
+ { mode: 0o755 },
106
+ )
60
107
 
61
108
  // Build explicitly so verification cannot inherit a machine-level
62
109
  // ignore-scripts setting and accidentally pack stale or missing output.
@@ -70,21 +117,14 @@ try {
70
117
  throw new Error(`expected one packed agent-bench tarball, found ${packedFiles.length}`)
71
118
  }
72
119
  const tarball = path.join(packDir, packedFiles[0])
120
+ await run('tar', ['-xzf', tarball, '-C', unpackDir], benchDir)
73
121
  const runtimePackage = await resolveRuntimePackage(runtimePackDir)
74
- const manifest = JSON.parse(await readFile(path.join(benchDir, 'package.json'), 'utf8'))
75
- const devDependencies = manifest.devDependencies
76
- if (
77
- typeof devDependencies?.['@types/node'] !== 'string' ||
78
- typeof devDependencies.typescript !== 'string' ||
79
- typeof devDependencies.tsx !== 'string' ||
80
- !devDependencies['@types/node'] ||
81
- !devDependencies.typescript ||
82
- !devDependencies.tsx
83
- ) {
84
- throw new Error(
85
- 'package verification requires @types/node, typescript, and tsx devDependencies',
86
- )
87
- }
122
+ const packedManifest = JSON.parse(
123
+ await readFile(path.join(unpackDir, 'package', 'package.json'), 'utf8'),
124
+ )
125
+ const nodeTypes = requiredPackedDevelopmentDependency(packedManifest, '@types/node')
126
+ requiredPackedDevelopmentDependency(packedManifest, 'typescript')
127
+ const tsx = requiredPackedDevelopmentDependency(packedManifest, 'tsx')
88
128
  const publicTsconfig = JSON.parse(
89
129
  await readFile(path.join(benchDir, 'tsconfig.public.json'), 'utf8'),
90
130
  )
@@ -105,9 +145,9 @@ try {
105
145
  : {}),
106
146
  },
107
147
  devDependencies: {
108
- '@types/node': devDependencies['@types/node'],
148
+ '@types/node': nodeTypes,
109
149
  typescript: TYPESCRIPT_5,
110
- tsx: devDependencies.tsx,
150
+ tsx,
111
151
  },
112
152
  },
113
153
  null,
@@ -122,6 +162,21 @@ try {
122
162
  path.join(consumerDir, 'index.mjs'),
123
163
  "import { resolveAdapter, runBenchmarks } from '@tangle-network/agent-bench'\nimport { ADAPTERS } from '@tangle-network/agent-bench/adapters'\nimport { createCragAdapter } from '@tangle-network/agent-bench/benchmarks/crag'\n\nif (typeof resolveAdapter !== 'function' || typeof runBenchmarks !== 'function') throw new Error('root exports are not executable')\nif (typeof ADAPTERS !== 'object' || typeof createCragAdapter !== 'function') throw new Error('subpath exports are not executable')\nif (resolveAdapter('crag').name !== 'crag') throw new Error('compiled adapter registry returned the wrong adapter')\nprocess.env.TOOLLM_FIXTURES = '1'\nconst toolLlmTasks = await resolveAdapter('toollm').loadTasks({ limit: 1 })\nif (toolLlmTasks.length !== 1 || toolLlmTasks[0]?.id !== '1') throw new Error('packed ToolLLM fixture loading failed')\n",
124
164
  )
165
+ await writeFile(
166
+ path.join(consumerDir, 'terminal-bench-absolute-venv.mjs'),
167
+ `import { createTerminalBenchAdapter } from '@tangle-network/agent-bench/benchmarks/terminal-bench'
168
+
169
+ const adapter = createTerminalBenchAdapter()
170
+ const tasks = await adapter.loadTasks({ ids: ['installed-absolute-venv'] })
171
+ if (tasks.length !== 1 || tasks[0]?.id !== 'installed-absolute-venv') {
172
+ throw new Error('packed Terminal-Bench adapter did not load through the absolute venv')
173
+ }
174
+ const score = await adapter.judge(tasks[0], 'echo installed-package-path')
175
+ if (!score.resolved || score.score !== 1) {
176
+ throw new Error(\`packed Terminal-Bench adapter did not judge through the absolute venv: \${JSON.stringify(score)}\`)
177
+ }
178
+ `,
179
+ )
125
180
  await writeFile(
126
181
  path.join(consumerDir, 'tsconfig.json'),
127
182
  `${JSON.stringify(
@@ -165,6 +220,10 @@ for name in sorted(expected):
165
220
  consumerDir,
166
221
  )
167
222
  await run('node', ['index.mjs'], consumerDir)
223
+ await run('node', ['terminal-bench-absolute-venv.mjs'], consumerDir, {
224
+ ...process.env,
225
+ TERMINAL_BENCH_VENV: terminalBenchVenv,
226
+ })
168
227
  await run('npm', ['exec', '--', 'tsc', '-p', 'tsconfig.json'], consumerDir)
169
228
  const typescript5 = await run('npm', ['exec', '--', 'tsc', '--version'], consumerDir)
170
229
  if (typescript5.stdout.trim() !== `Version ${TYPESCRIPT_5}`) {
@@ -228,8 +287,16 @@ for name in sorted(expected):
228
287
  })
229
288
  }
230
289
  console.log(
231
- `packed consumer verified: ${manifest.name}@${manifest.version} with @tangle-network/agent-runtime@${runtimeManifest.version}, TypeScript ${TYPESCRIPT_5} and ${TYPESCRIPT_6}; prepared ${prepareProof.executionPlanDigest}`,
290
+ `packed consumer verified: ${packedManifest.name}@${packedManifest.version} with @tangle-network/agent-runtime@${runtimeManifest.version}, TypeScript ${TYPESCRIPT_5} and ${TYPESCRIPT_6}, absolute Terminal-Bench venv; prepared ${prepareProof.executionPlanDigest}`,
232
291
  )
233
292
  } finally {
234
293
  await rm(scratch, { recursive: true, force: true })
235
294
  }
295
+
296
+ function requiredPackedDevelopmentDependency(packageJson, name) {
297
+ const version = packageJson.devDependencies?.[name]
298
+ if (typeof version !== 'string' || version.length === 0 || version.startsWith('catalog:')) {
299
+ throw new Error(`packed consumer requires a resolved ${name} development dependency`)
300
+ }
301
+ return version
302
+ }
@@ -435,7 +435,7 @@ ${proofArm === 'success' ? "(task / 'src/status.txt').write_text('ready\\nowner=
435
435
  workspace: taskWorkspace,
436
436
  evaluatorTaskContainer: container,
437
437
  limits: {
438
- timeoutMs: 60_000,
438
+ timeoutMs: 180_000,
439
439
  maxSteps: 8,
440
440
  maxModelCalls: 0,
441
441
  maxInputTokens: 0,
@@ -671,12 +671,14 @@ ${proofArm === 'success' ? "(task / 'src/status.txt').write_text('ready\\nowner=
671
671
  )
672
672
  }
673
673
  assertTreeOmits(scratch, 'zero-model-proof')
674
- const usage = finalized.receipt.value.usage
674
+ const usage = finalized.receipt.value.modelSettlement.material.usage
675
675
  if (
676
676
  usage.modelCalls !== 0 ||
677
677
  usage.inputTokens !== 0 ||
678
678
  usage.outputTokens !== 0 ||
679
- usage.costUsd !== 0 ||
679
+ usage.cachedInputTokens !== 0 ||
680
+ usage.reasoningTokens !== 0 ||
681
+ usage.costUsdNanos !== 0 ||
680
682
  finalized.receipt.value.trace.modelCallCount !== 0
681
683
  ) {
682
684
  throw new Error(`runtime minted nonzero usage for a zero-model run: ${JSON.stringify(usage)}`)
@@ -691,7 +693,7 @@ ${proofArm === 'success' ? "(task / 'src/status.txt').write_text('ready\\nowner=
691
693
  modelCalls: usage.modelCalls,
692
694
  inputTokens: usage.inputTokens,
693
695
  outputTokens: usage.outputTokens,
694
- costUsd: usage.costUsd,
696
+ costUsd: usage.costUsdNanos / 1_000_000_000,
695
697
  pierContextUsage: null,
696
698
  profileExcludedByVerifier: true,
697
699
  container: {
@@ -4,7 +4,13 @@ import { mkdtemp, readFile, rm, writeFile } from 'node:fs/promises'
4
4
  import test from 'node:test'
5
5
  import { tmpdir } from 'node:os'
6
6
  import { join } from 'node:path'
7
- import { resolveBenchPython, runStagedJudge } from './_harness'
7
+ import {
8
+ benchRoot,
9
+ resolveBenchPython,
10
+ runStagedJudge,
11
+ venvBin,
12
+ venvBinAt,
13
+ } from './_harness'
8
14
 
9
15
  const digest = (bytes: Uint8Array): `sha256:${string}` =>
10
16
  `sha256:${createHash('sha256').update(bytes).digest('hex')}`
@@ -31,6 +37,15 @@ test('resolveBenchPython rejects relative and empty interpreter paths', () => {
31
37
  )
32
38
  })
33
39
 
40
+ test('venv executable paths support package-owned and external environments', () => {
41
+ assert.equal(venvBinAt('/srv/terminal-bench', 'tb'), join('/srv/terminal-bench', 'bin', 'tb'))
42
+ assert.equal(
43
+ venvBinAt('.venv-commit0', 'python'),
44
+ join(benchRoot, '.venv-commit0', 'bin', 'python'),
45
+ )
46
+ assert.equal(venvBin('python'), venvBinAt('.venv', 'python'))
47
+ })
48
+
34
49
  test('runStagedJudge terminates a hung evaluator at its explicit timeout', async () => {
35
50
  const started = Date.now()
36
51
  await assert.rejects(
@@ -82,13 +82,20 @@ export const venvPython = resolveBenchPython()
82
82
  /** Interpreter for a NAMED isolated venv (e.g. `.venv-commit0`). Benches whose pip
83
83
  * deps conflict with the shared `.venv` (commit0 downgrades pydantic/sqlalchemy)
84
84
  * get their own venv and pass its python explicitly — keeping the shared one clean. */
85
- export const venvPythonAt = (venvDir: string): string => join(benchRoot, venvDir, 'bin', 'python')
85
+ export const venvPythonAt = (venvDir: string): string => venvBinAt(venvDir, 'python')
86
+
87
+ /** Resolve an executable in an isolated venv. Relative venv paths are package-owned;
88
+ * absolute paths allow installed consumers to keep large environments elsewhere. */
89
+ export function venvBinAt(venvDir: string, name: string): string {
90
+ return join(resolve(benchRoot, venvDir), 'bin', name)
91
+ }
92
+
86
93
  /** Report/transcript reads are large; 256 MiB matches the SWE harness budget. */
87
94
  export const bigBuffer = 1024 * 1024 * 256
88
95
 
89
96
  /** Path to a named executable inside the bench venv (e.g. `venvBin('tb')`). */
90
97
  export function venvBin(name: string): string {
91
- return join(benchRoot, '.venv', 'bin', name)
98
+ return venvBinAt('.venv', name)
92
99
  }
93
100
 
94
101
  /**
@@ -25,6 +25,7 @@ import {
25
25
  runVenvPython,
26
26
  safeRunId,
27
27
  stageFile,
28
+ venvBinAt,
28
29
  venvPythonAt,
29
30
  } from './_harness'
30
31
  import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './types'
@@ -34,7 +35,7 @@ import type { BenchmarkAdapter, BenchScore, BenchTask, LoadOptions } from './typ
34
35
  // override the env without reloading this module.
35
36
  const terminalBenchVenvDir = (): string => process.env.TERMINAL_BENCH_VENV ?? '.venv-terminal-bench'
36
37
  const terminalBenchPython = (): string => venvPythonAt(terminalBenchVenvDir())
37
- const terminalBenchBin = (): string => join(benchRoot, terminalBenchVenvDir(), 'bin', 'tb')
38
+ const terminalBenchBin = (): string => venvBinAt(terminalBenchVenvDir(), 'tb')
38
39
 
39
40
  // Pinned dataset: the 0.1.1 core set is patched for terminal-bench >=0.2.4 (the
40
41
  // installed CLI) and is the published launch task set. name==version is what `tb
@@ -109,6 +109,8 @@ const baseRec = (attempts: AttemptRecord[], over: Partial<RunRecord> = {}): RunR
109
109
  assert.equal(r0?.commitSha, 'abc123')
110
110
  assert.equal(r0?.tokenUsage.input, 100, 'real tokens carried (not zeroed)')
111
111
  assert.equal(r0?.costUsd, 0.01, 'real cost carried')
112
+ assert.deepEqual(r0?.costProvenance, { kind: 'observed', usd: 0.01 }, 'reported cost remains observed')
113
+ assert.equal(r0?.terminalOutcome, 'succeeded', 'failed task quality is not an execution failure')
112
114
  assert.equal(r0?.prompt, 'q0', 'verbatim prompt survives the validator')
113
115
  assert.equal(r0?.completion, 'alpha', 'verbatim completion survives the validator')
114
116
  assert.equal(r0?.outcome.searchScore, 0, 'search split → searchScore from attempt score')
@@ -117,6 +119,17 @@ const baseRec = (attempts: AttemptRecord[], over: Partial<RunRecord> = {}): RunR
117
119
  assert.notEqual(r0?.runId, r1?.runId, 'per-attempt runIds are distinct')
118
120
  }
119
121
 
122
+ // --- attempt error is execution state, not a fabricated zero-quality label ---
123
+ {
124
+ const { records, unmappable } = await benchRecordToCorpusRecords(
125
+ baseRec([{ ...measuredAttempt(0, 'partial output', false), error: 'provider disconnected' }]),
126
+ { commitSha: 'abc123', model: 'gpt-5-2025-08-07' },
127
+ )
128
+ assert.equal(unmappable.length, 0)
129
+ assert.equal(records[0]?.terminalOutcome, 'failed')
130
+ assert.equal(records[0]?.outcome.searchScore, 0, 'task quality remains independently recorded')
131
+ }
132
+
120
133
  // --- unmeasured economics → unmappable, never forged with phantom zeros ---
121
134
  {
122
135
  const bare: AttemptRecord = { round: 0, prompt: 'q', output: 'x', valid: true, eventCount: 0, eventTypes: {} }
package/src/corpus.ts CHANGED
@@ -288,7 +288,11 @@ export async function benchRecordToCorpusRecords(
288
288
  commitSha: opts.commitSha,
289
289
  wallMs: a.wallMs as number,
290
290
  costUsd: a.costUsd as number,
291
+ // Attempt costs are present only when the worker reported them. Missing
292
+ // costs exited above rather than becoming a made-up zero.
293
+ costProvenance: { kind: 'observed', usd: a.costUsd as number },
291
294
  tokenUsage: { input: a.tokensIn as number, output: a.tokensOut as number },
295
+ terminalOutcome: a.error === undefined ? 'succeeded' : 'failed',
292
296
  outcome: {
293
297
  ...(splitTag === 'holdout' ? { holdoutScore: score } : { searchScore: score }),
294
298
  raw: { valid: a.valid === true ? 1 : 0, score },
@@ -14,8 +14,8 @@
14
14
  */
15
15
  import { readFileSync, readdirSync } from 'node:fs'
16
16
  import { join } from 'node:path'
17
- import type { AgentProfile } from '@tangle-network/sandbox'
18
- import { defineInlineResource } from '@tangle-network/sandbox'
17
+ import type { AgentProfile } from '@tangle-network/agent-interface'
18
+ import { defineInlineResource } from '@tangle-network/agent-interface'
19
19
 
20
20
  export interface ProfileCoordinate {
21
21
  /** Coordinate id (the COORDINATE= knob value). */
@@ -141,10 +141,11 @@ interface Ctx {
141
141
  stats: BackfillStats
142
142
  }
143
143
 
144
- function baseLine(ctx: Ctx): Pick<RolloutLine, 'schema' | 'run_id' | 'provenance'> {
144
+ function baseLine(ctx: Ctx): Pick<RolloutLine, 'schema' | 'run_id' | 'experiment_id' | 'provenance'> {
145
145
  return {
146
146
  schema: ROLLOUT_SCHEMA,
147
147
  run_id: ctx.runId,
148
+ experiment_id: null,
148
149
  provenance: { captured_at: ctx.capturedAt, capture: 'backfill' },
149
150
  }
150
151
  }
@@ -216,6 +217,7 @@ async function emitCellLines(
216
217
  reward,
217
218
  reward_source: reward === null ? null : OFFICIAL_JUDGE,
218
219
  verdict: judgeVerdict,
220
+ realness_gated: false,
219
221
  metrics: {
220
222
  resolved: artifact?.resolved ?? null,
221
223
  verify_pass: artifact?.verifyPass ?? null,
@@ -335,6 +337,7 @@ function workerLine(
335
337
  reward,
336
338
  reward_source: reward === null ? null : `${OFFICIAL_JUDGE}/inherited`,
337
339
  verdict: null,
340
+ realness_gated: false,
338
341
  metrics: {
339
342
  worker_cwd: cwd,
340
343
  session_agent: session?.agent ?? null,
@@ -504,6 +507,7 @@ async function emitProposerLines(ctx: Ctx, lines: RolloutLine[], entries: Rollou
504
507
  reward,
505
508
  reward_source: reward === null ? null : `${OFFICIAL_JUDGE}/candidate-resolved-fraction`,
506
509
  verdict: null,
510
+ realness_gated: false,
507
511
  metrics: {
508
512
  resolved_count: entry?.outcome.resolvedCount ?? null,
509
513
  instance_count: ctx.instanceCount,
@@ -194,9 +194,12 @@ export function createSettleCapture(opts: SettleCaptureOptions): SettleCapture {
194
194
  const log = opts.log ?? (() => {})
195
195
  const dbPath = opts.opencodeDb ?? DEFAULT_OPENCODE_DB
196
196
 
197
- const base = (capturedAt: string): Pick<RolloutLine, 'schema' | 'run_id'> & { provenance: RolloutLine['provenance'] } => ({
197
+ const base = (
198
+ capturedAt: string,
199
+ ): Pick<RolloutLine, 'schema' | 'run_id' | 'experiment_id'> & { provenance: RolloutLine['provenance'] } => ({
198
200
  schema: ROLLOUT_SCHEMA,
199
201
  run_id: opts.runId,
202
+ experiment_id: null,
200
203
  provenance: { captured_at: capturedAt, capture: 'settle-time' },
201
204
  })
202
205
 
@@ -232,6 +235,7 @@ export function createSettleCapture(opts: SettleCaptureOptions): SettleCapture {
232
235
  reward,
233
236
  reward_source: reward === null ? null : OFFICIAL_JUDGE,
234
237
  verdict: args.judgeVerdict,
238
+ realness_gated: false,
235
239
  metrics: {
236
240
  ...args.metrics,
237
241
  ...(args.splitVisibility !== null ? { split_visibility: args.splitVisibility } : {}),
@@ -311,6 +315,7 @@ export function createSettleCapture(opts: SettleCaptureOptions): SettleCapture {
311
315
  reward: v2.reward,
312
316
  reward_source: v2.reward === null && v2.deliveredMatch !== 'unknown' ? null : WORKER_REWARD_SOURCE_V2,
313
317
  verdict: null,
318
+ realness_gated: false,
314
319
  metrics: {
315
320
  worker_label: worker.label,
316
321
  worker_cwd: worker.cwd,
@@ -400,6 +405,7 @@ export function createSettleCapture(opts: SettleCaptureOptions): SettleCapture {
400
405
  reward,
401
406
  reward_source: PROPOSER_REWARD_SOURCE_V2,
402
407
  verdict: null,
408
+ realness_gated: false,
403
409
  metrics: {
404
410
  resolved_count: args.candResolved,
405
411
  baseline_resolved_count: args.baselineResolved,
@@ -17,7 +17,7 @@
17
17
  * shape — a `transport:'http'` server at the router's `/v1/search/mcp` endpoint,
18
18
  * provider pinned via the `?provider=` query param.
19
19
  */
20
- import type { AgentProfile } from '@tangle-network/sandbox'
20
+ import type { AgentProfile } from '@tangle-network/agent-interface'
21
21
 
22
22
  export type SearchArm = 'native' | 'off' | { provider: string }
23
23
 
@@ -14,7 +14,8 @@
14
14
  *
15
15
  * Run: dotenvx run -f ~/company/devops/secrets/.env.keys -- pnpm exec tsx bench/src/skill-sandbox-smoke.mts
16
16
  */
17
- import { Sandbox, defineInlineResource } from '@tangle-network/sandbox'
17
+ import { defineInlineResource } from '@tangle-network/agent-interface'
18
+ import { Sandbox } from '@tangle-network/sandbox'
18
19
 
19
20
  const must = (k: string): string => {
20
21
  const v = process.env[k]
@@ -233,7 +233,7 @@ export function innerSmokeJudge(): JudgeConfig<SmokeVerdict, GepaSeatScenario> {
233
233
  // ---------------------------------------------------------------------------
234
234
 
235
235
  export const GEPA_PYTHON_INSTALL_HINT =
236
- 'install `agent-eval-rpc==0.126.6`, then install ' +
236
+ 'install `agent-eval-rpc==0.131.0`, then install ' +
237
237
  '`gepa[full] @ git+https://github.com/gepa-ai/gepa.git@f919db0a622e2e9f9204779b81fe00cc1b2d808f`'
238
238
 
239
239
  export type GepaMethodFactory = (
@@ -7,7 +7,8 @@
7
7
  * path improve() rides.
8
8
  */
9
9
 
10
- import { mkdtempSync, readFileSync, writeFileSync } from 'node:fs'
10
+ import { execFileSync } from 'node:child_process'
11
+ import { mkdtempSync, readFileSync } from 'node:fs'
11
12
  import { tmpdir } from 'node:os'
12
13
  import { join } from 'node:path'
13
14
  import { describe, expect, it } from 'vitest'
@@ -22,40 +23,41 @@ import {
22
23
 
23
24
  const ATTRIBUTION = { channel: 'agent', phase: 'search.baseline', model: 'm' }
24
25
 
25
- /** A durable event line in the exact shape cost-ledger.jsonl persists. */
26
- const line = (record: Record<string, unknown>): string =>
27
- `${JSON.stringify({ version: 1, record })}\n`
28
-
29
- /** Write a synthetic ledger: one settled pair + one crash-orphaned pending. */
26
+ /**
27
+ * Write one settled receipt and then terminate a process with a real pending
28
+ * call. The child uses the public ledger API so this fixture cannot shadow its
29
+ * private JSONL event format.
30
+ */
30
31
  function writeCrashedLedger(dir: string): void {
31
- const settledPending = {
32
- status: 'pending',
33
- callId: 'settled-1',
34
- ...ATTRIBUTION,
35
- actor: 'worker:astropy#r0',
36
- timestamp: 1_000,
37
- }
38
- const settledReceipt = {
39
- ...settledPending,
40
- status: 'settled',
41
- inputTokens: 10,
42
- outputTokens: 5,
43
- costUsd: 0.01,
44
- costUnknown: false,
45
- actualCostUsd: 0.01,
46
- }
47
- const orphanPending = {
48
- status: 'pending',
49
- callId: 'orphan-1',
50
- ...ATTRIBUTION,
51
- actor: 'worker:xarray#r0',
52
- timestamp: 2_000,
53
- tags: { cellId: 'pydata__xarray-4687:0' },
54
- }
55
- writeFileSync(
56
- join(dir, 'cost-ledger.jsonl'),
57
- line(settledPending) + line(settledReceipt) + line(orphanPending),
58
- )
32
+ const child = `
33
+ import { createRunCostLedger, fsCampaignStorage } from '@tangle-network/agent-eval/campaign'
34
+ const runDir = process.env.COST_LEDGER_RUN_DIR
35
+ if (typeof runDir !== 'string' || runDir.length === 0) throw new Error('missing COST_LEDGER_RUN_DIR')
36
+ const attribution = { channel: 'agent', phase: 'search.baseline', model: 'm' }
37
+ const ledger = createRunCostLedger({ storage: fsCampaignStorage(), runDir })
38
+ await ledger.runPaidCall({
39
+ ...attribution,
40
+ callId: 'settled-1',
41
+ actor: 'worker:astropy#r0',
42
+ execute: async () => 'settled',
43
+ receipt: () => ({ model: 'm', inputTokens: 10, outputTokens: 5, actualCostUsd: 0.01 }),
44
+ })
45
+ let started
46
+ const pending = new Promise((resolve) => { started = resolve })
47
+ void ledger.runPaidCall({
48
+ ...attribution,
49
+ callId: 'orphan-1',
50
+ actor: 'worker:xarray#r0',
51
+ tags: { cellId: 'pydata__xarray-4687:0' },
52
+ execute: async () => { started(); return await new Promise(() => {}) },
53
+ receipt: () => ({ model: 'm', inputTokens: 0, outputTokens: 0, actualCostUsd: 0 }),
54
+ })
55
+ await pending
56
+ `
57
+ execFileSync(process.execPath, ['--input-type=module', '--eval', child], {
58
+ cwd: process.cwd(),
59
+ env: { ...process.env, COST_LEDGER_RUN_DIR: dir },
60
+ })
59
61
  }
60
62
 
61
63
  const openLedger = (dir: string) =>
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}