@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,715 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process'
|
|
2
|
+
import { createHash } from 'node:crypto'
|
|
3
|
+
import {
|
|
4
|
+
chmodSync,
|
|
5
|
+
cpSync,
|
|
6
|
+
lstatSync,
|
|
7
|
+
mkdirSync,
|
|
8
|
+
mkdtempSync,
|
|
9
|
+
readFileSync,
|
|
10
|
+
readdirSync,
|
|
11
|
+
rmSync,
|
|
12
|
+
writeFileSync,
|
|
13
|
+
} from 'node:fs'
|
|
14
|
+
import { tmpdir } from 'node:os'
|
|
15
|
+
import path from 'node:path'
|
|
16
|
+
import { fileURLToPath } from 'node:url'
|
|
17
|
+
|
|
18
|
+
import { canonicalJson, InMemoryTraceStore } from '@tangle-network/agent-eval'
|
|
19
|
+
import {
|
|
20
|
+
sealCandidateBenchmarkSuite,
|
|
21
|
+
sealCandidateBenchmarkTask,
|
|
22
|
+
} from '@tangle-network/agent-eval/contract'
|
|
23
|
+
import type {
|
|
24
|
+
AgentCandidateArtifactRef,
|
|
25
|
+
AgentCandidateBundle,
|
|
26
|
+
AgentCandidateWorkspaceSnapshotEvidence,
|
|
27
|
+
Sha256Digest,
|
|
28
|
+
} from '@tangle-network/agent-interface'
|
|
29
|
+
import {
|
|
30
|
+
createAgentCandidateWorkspacePort,
|
|
31
|
+
disposePreparedAgentCandidateExecution,
|
|
32
|
+
FileAgentCandidateExecutionClaimStore,
|
|
33
|
+
prepareAgentCandidateExecution,
|
|
34
|
+
type AgentCandidateExecutionPorts,
|
|
35
|
+
type AgentCandidateOutputArtifactPort,
|
|
36
|
+
type AgentCandidateTaskExecution,
|
|
37
|
+
type ResolvedAgentCandidateContainer,
|
|
38
|
+
sealAgentCandidateBundle,
|
|
39
|
+
verifyAgentCandidateBundle,
|
|
40
|
+
} from '@tangle-network/agent-runtime'
|
|
41
|
+
|
|
42
|
+
import { executePreparedPierCandidate } from '../src/pier-agent'
|
|
43
|
+
import { createPierResultGrader } from '../src/pier-result-grader'
|
|
44
|
+
import { FilePierCandidateTrialController } from '../src/pier-trial-controller'
|
|
45
|
+
|
|
46
|
+
const pinnedPierCommit = 'e69a20e4e0ac073ec71fde0274bab3d9f40bac87'
|
|
47
|
+
const pinnedPierVersion = '0.3.0'
|
|
48
|
+
const modelRequest = 'openai/gpt-5.4'
|
|
49
|
+
const fixtureImage = 'ghcr.io/tangle-network/devcontainers/universal:latest'
|
|
50
|
+
const prepareOnly = process.env.PIER_PREPARE_ONLY === '1'
|
|
51
|
+
const proofArm = process.env.PIER_PROOF_ARM
|
|
52
|
+
if (proofArm !== 'failure' && proofArm !== 'success') {
|
|
53
|
+
throw new Error('PIER_PROOF_ARM must be explicitly set to failure or success')
|
|
54
|
+
}
|
|
55
|
+
const expectedReward = proofArm === 'success' ? 1 : 0
|
|
56
|
+
const expectedPatchApplied = proofArm === 'success' ? 1 : 0
|
|
57
|
+
const benchDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..')
|
|
58
|
+
const pierRepo = path.resolve(process.env.PIER_REPO ?? path.join(benchDir, '..', '..', 'pier'))
|
|
59
|
+
const fixtureSource = path.join(benchDir, 'fixtures', 'pier-agent', 'no-model-task')
|
|
60
|
+
const scratch = mkdtempSync(path.join(tmpdir(), 'agent-bench-pier-runtime-'))
|
|
61
|
+
const taskDir = path.join(scratch, 'task')
|
|
62
|
+
const taskRoot = path.join(scratch, 'task-workspace')
|
|
63
|
+
const candidateRoot = path.join(scratch, 'candidate-workspace')
|
|
64
|
+
const profileRoot = path.join(scratch, 'profile-workspace')
|
|
65
|
+
const jobsDir = path.join(scratch, 'jobs')
|
|
66
|
+
|
|
67
|
+
function output(
|
|
68
|
+
command: string,
|
|
69
|
+
args: string[],
|
|
70
|
+
cwd = benchDir,
|
|
71
|
+
env: NodeJS.ProcessEnv = process.env,
|
|
72
|
+
): string {
|
|
73
|
+
return execFileSync(command, args, {
|
|
74
|
+
cwd,
|
|
75
|
+
env,
|
|
76
|
+
encoding: 'utf8',
|
|
77
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
78
|
+
timeout: 10 * 60_000,
|
|
79
|
+
maxBuffer: 20 * 1024 * 1024,
|
|
80
|
+
}).trim()
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function sha256(bytes: Uint8Array): Sha256Digest {
|
|
84
|
+
return `sha256:${createHash('sha256').update(bytes).digest('hex')}`
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function canonicalBytes(value: unknown): Buffer {
|
|
88
|
+
return Buffer.from(canonicalJson(value), 'utf8')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function sealCanonical<T extends object>(material: T): T & { digest: Sha256Digest } {
|
|
92
|
+
return { ...material, digest: sha256(canonicalBytes(material)) }
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function embedded(bytes: Uint8Array) {
|
|
96
|
+
return {
|
|
97
|
+
encoding: 'base64' as const,
|
|
98
|
+
content: Buffer.from(bytes).toString('base64'),
|
|
99
|
+
sha256: sha256(bytes),
|
|
100
|
+
byteLength: bytes.byteLength,
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function workspaceSnapshot(
|
|
105
|
+
root: string,
|
|
106
|
+
paths: readonly string[],
|
|
107
|
+
): AgentCandidateWorkspaceSnapshotEvidence {
|
|
108
|
+
const files = paths
|
|
109
|
+
.map((relative) => {
|
|
110
|
+
const absolute = path.join(root, relative)
|
|
111
|
+
const bytes = readFileSync(absolute)
|
|
112
|
+
const mode = lstatSync(absolute).mode & 0o777
|
|
113
|
+
if (mode !== 0o644 && mode !== 0o755) {
|
|
114
|
+
throw new Error(`unsupported fixture mode ${mode.toString(8)}: ${relative}`)
|
|
115
|
+
}
|
|
116
|
+
return {
|
|
117
|
+
path: relative,
|
|
118
|
+
mode: mode as 0o644 | 0o755,
|
|
119
|
+
sha256: sha256(bytes),
|
|
120
|
+
byteLength: bytes.byteLength,
|
|
121
|
+
}
|
|
122
|
+
})
|
|
123
|
+
.sort((left, right) => left.path.localeCompare(right.path))
|
|
124
|
+
const material = {
|
|
125
|
+
kind: 'agent-candidate-workspace-manifest' as const,
|
|
126
|
+
files,
|
|
127
|
+
} satisfies AgentCandidateWorkspaceSnapshotEvidence['material']
|
|
128
|
+
const manifest = canonicalBytes(material)
|
|
129
|
+
return {
|
|
130
|
+
kind: 'agent-candidate-workspace-snapshot',
|
|
131
|
+
digest: sha256(manifest),
|
|
132
|
+
material,
|
|
133
|
+
manifest: embedded(manifest),
|
|
134
|
+
archive: embedded(Buffer.from(`pre-materialized:${sha256(manifest)}`, 'utf8')),
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function deterministicRepository(root: string, seed: string): { commit: string; tree: string } {
|
|
139
|
+
mkdirSync(path.join(root, 'src'), { recursive: true })
|
|
140
|
+
cpSync(seed, path.join(root, 'src', 'status.txt'))
|
|
141
|
+
chmodSync(path.join(root, 'src', 'status.txt'), 0o644)
|
|
142
|
+
output('git', ['init', '-b', 'main', root])
|
|
143
|
+
output('git', ['-C', root, 'config', 'user.email', 'fixture@tangle.tools'])
|
|
144
|
+
output('git', ['-C', root, 'config', 'user.name', 'Tangle Fixture'])
|
|
145
|
+
output('git', [
|
|
146
|
+
'-C',
|
|
147
|
+
root,
|
|
148
|
+
'remote',
|
|
149
|
+
'add',
|
|
150
|
+
'origin',
|
|
151
|
+
'git@github.com:tangle-network/agent-bench-pier-fixture.git',
|
|
152
|
+
])
|
|
153
|
+
output('git', ['-c', 'core.hooksPath=/dev/null', '-C', root, 'add', '-A'])
|
|
154
|
+
output(
|
|
155
|
+
'git',
|
|
156
|
+
['-c', 'core.hooksPath=/dev/null', '-C', root, 'commit', '-m', 'baseline'],
|
|
157
|
+
benchDir,
|
|
158
|
+
{
|
|
159
|
+
...process.env,
|
|
160
|
+
GIT_AUTHOR_DATE: '2000-01-01T00:00:00Z',
|
|
161
|
+
GIT_COMMITTER_DATE: '2000-01-01T00:00:00Z',
|
|
162
|
+
},
|
|
163
|
+
)
|
|
164
|
+
return {
|
|
165
|
+
commit: output('git', ['-C', root, 'rev-parse', 'HEAD']),
|
|
166
|
+
tree: output('git', ['-C', root, 'rev-parse', 'HEAD^{tree}']),
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function publicOciIdentity(
|
|
171
|
+
image: string,
|
|
172
|
+
): { indexDigest: Sha256Digest; manifestDigest: Sha256Digest } {
|
|
173
|
+
const material = JSON.parse(
|
|
174
|
+
output('docker', ['buildx', 'imagetools', 'inspect', image, '--format', '{{json .Manifest}}']),
|
|
175
|
+
) as {
|
|
176
|
+
digest?: string
|
|
177
|
+
manifests?: Array<{
|
|
178
|
+
digest?: string
|
|
179
|
+
platform?: { os?: string; architecture?: string }
|
|
180
|
+
}>
|
|
181
|
+
}
|
|
182
|
+
const topDigest = material.digest
|
|
183
|
+
if (!topDigest?.match(/^sha256:[a-f0-9]{64}$/)) {
|
|
184
|
+
throw new Error(`public image omitted a valid index digest: ${topDigest}`)
|
|
185
|
+
}
|
|
186
|
+
const selected = material.manifests?.find(
|
|
187
|
+
(entry) => entry.platform?.os === 'linux' && entry.platform.architecture === 'amd64',
|
|
188
|
+
)
|
|
189
|
+
const manifestDigest = selected?.digest
|
|
190
|
+
if (!manifestDigest) throw new Error('public image has no linux/amd64 manifest')
|
|
191
|
+
if (!manifestDigest.match(/^sha256:[a-f0-9]{64}$/)) {
|
|
192
|
+
throw new Error(`public image returned an invalid platform manifest: ${manifestDigest}`)
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
indexDigest: topDigest as Sha256Digest,
|
|
196
|
+
manifestDigest: manifestDigest as Sha256Digest,
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function findTrialResult(root: string): { path: string; value: Record<string, any> } | undefined {
|
|
201
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
202
|
+
if (!entry.isDirectory()) continue
|
|
203
|
+
const child = path.join(root, entry.name)
|
|
204
|
+
const candidate = path.join(child, 'result.json')
|
|
205
|
+
try {
|
|
206
|
+
const value = JSON.parse(readFileSync(candidate, 'utf8')) as Record<string, any>
|
|
207
|
+
if (typeof value.trial_name === 'string') return { path: candidate, value }
|
|
208
|
+
} catch {}
|
|
209
|
+
const nested = findTrialResult(child)
|
|
210
|
+
if (nested) return nested
|
|
211
|
+
}
|
|
212
|
+
return undefined
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function assertTreeOmits(root: string, forbidden: string): void {
|
|
216
|
+
for (const entry of readdirSync(root, { withFileTypes: true })) {
|
|
217
|
+
const absolute = path.join(root, entry.name)
|
|
218
|
+
if (entry.isDirectory()) {
|
|
219
|
+
assertTreeOmits(absolute, forbidden)
|
|
220
|
+
} else if (entry.isFile() && readFileSync(absolute).includes(Buffer.from(forbidden))) {
|
|
221
|
+
throw new Error(`protected value persisted in ${path.relative(root, absolute)}`)
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function outputArtifactStore(graderBytes: Uint8Array): {
|
|
227
|
+
outputArtifacts: AgentCandidateOutputArtifactPort
|
|
228
|
+
graderArtifact: AgentCandidateArtifactRef
|
|
229
|
+
} {
|
|
230
|
+
const stored = new Map<string, Uint8Array>()
|
|
231
|
+
const put = (bytes: Uint8Array, purpose: string): AgentCandidateArtifactRef => {
|
|
232
|
+
const detached = Uint8Array.from(bytes)
|
|
233
|
+
const digest = sha256(detached)
|
|
234
|
+
const artifact: AgentCandidateArtifactRef = {
|
|
235
|
+
locator: {
|
|
236
|
+
kind: 's3',
|
|
237
|
+
bucket: 'agent-bench-pier-proof',
|
|
238
|
+
key: `${purpose}/${digest.slice('sha256:'.length)}`,
|
|
239
|
+
},
|
|
240
|
+
sha256: digest,
|
|
241
|
+
byteLength: detached.byteLength,
|
|
242
|
+
}
|
|
243
|
+
stored.set(digest, detached)
|
|
244
|
+
return artifact
|
|
245
|
+
}
|
|
246
|
+
const graderArtifact = put(graderBytes, 'graders')
|
|
247
|
+
return {
|
|
248
|
+
graderArtifact,
|
|
249
|
+
outputArtifacts: {
|
|
250
|
+
put: async ({ bytes, purpose, signal }) => {
|
|
251
|
+
signal?.throwIfAborted()
|
|
252
|
+
return put(bytes, purpose)
|
|
253
|
+
},
|
|
254
|
+
read: async (artifact) => {
|
|
255
|
+
const bytes = stored.get(artifact.sha256)
|
|
256
|
+
if (!bytes) throw new Error(`missing Pier proof artifact ${artifact.sha256}`)
|
|
257
|
+
return Uint8Array.from(bytes)
|
|
258
|
+
},
|
|
259
|
+
},
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
if (!prepareOnly) {
|
|
265
|
+
const pierHead = output('git', ['rev-parse', 'HEAD'], pierRepo)
|
|
266
|
+
if (pierHead !== pinnedPierCommit) {
|
|
267
|
+
throw new Error(`Pier checkout mismatch: expected ${pinnedPierCommit}, got ${pierHead}`)
|
|
268
|
+
}
|
|
269
|
+
const pierStatus = output('git', ['status', '--porcelain'], pierRepo)
|
|
270
|
+
if (pierStatus !== '') throw new Error(`Pier checkout must be clean: ${pierStatus}`)
|
|
271
|
+
const pierVersion = output('uv', ['run', 'pier', '--version'], pierRepo)
|
|
272
|
+
if (pierVersion !== pinnedPierVersion) {
|
|
273
|
+
throw new Error(`Pier version mismatch: expected ${pinnedPierVersion}, got ${pierVersion}`)
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
cpSync(fixtureSource, taskDir, { recursive: true })
|
|
278
|
+
for (const relative of ['environment/seed/src/status.txt', 'tests/seed/src/status.txt']) {
|
|
279
|
+
chmodSync(path.join(taskDir, relative), 0o644)
|
|
280
|
+
}
|
|
281
|
+
for (const relative of ['pre_artifacts.sh', 'tests/test.sh']) {
|
|
282
|
+
chmodSync(path.join(taskDir, relative), 0o755)
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const contextDigest = sha256(
|
|
286
|
+
Buffer.concat([
|
|
287
|
+
readFileSync(path.join(taskDir, 'environment', 'Dockerfile')),
|
|
288
|
+
readFileSync(path.join(taskDir, 'environment', 'seed', 'src', 'status.txt')),
|
|
289
|
+
]),
|
|
290
|
+
).slice(7, 23)
|
|
291
|
+
const identity = prepareOnly
|
|
292
|
+
? {
|
|
293
|
+
indexDigest: `sha256:${'1'.repeat(64)}` as Sha256Digest,
|
|
294
|
+
manifestDigest: `sha256:${'2'.repeat(64)}` as Sha256Digest,
|
|
295
|
+
}
|
|
296
|
+
: publicOciIdentity(fixtureImage)
|
|
297
|
+
const pinnedImage = `${fixtureImage}@${identity.indexDigest}`
|
|
298
|
+
if (!prepareOnly) output('docker', ['pull', '--platform', 'linux/amd64', pinnedImage])
|
|
299
|
+
const platform = prepareOnly
|
|
300
|
+
? 'linux/amd64'
|
|
301
|
+
: output('docker', [
|
|
302
|
+
'image',
|
|
303
|
+
'inspect',
|
|
304
|
+
'--format',
|
|
305
|
+
'{{.Os}}/{{.Architecture}}',
|
|
306
|
+
pinnedImage,
|
|
307
|
+
])
|
|
308
|
+
if (platform !== 'linux/amd64') throw new Error(`fixture image platform drifted: ${platform}`)
|
|
309
|
+
|
|
310
|
+
const configPath = path.join(taskDir, 'task.toml')
|
|
311
|
+
const config = readFileSync(configPath, 'utf8')
|
|
312
|
+
writeFileSync(
|
|
313
|
+
configPath,
|
|
314
|
+
config.replace(
|
|
315
|
+
'[environment]\n',
|
|
316
|
+
`[environment]\ndocker_image = "${pinnedImage}"\nos = "linux"\n`,
|
|
317
|
+
),
|
|
318
|
+
)
|
|
319
|
+
mkdirSync(candidateRoot)
|
|
320
|
+
mkdirSync(profileRoot)
|
|
321
|
+
const instruction = readFileSync(path.join(taskDir, 'instruction.md'), 'utf8')
|
|
322
|
+
const runner = `import pathlib, sys
|
|
323
|
+
task = pathlib.Path.cwd()
|
|
324
|
+
profile = task / 'AGENTS.md'
|
|
325
|
+
assert profile.is_file() and profile.read_text().strip()
|
|
326
|
+
assert sys.argv[-1] == ${JSON.stringify(instruction)}
|
|
327
|
+
${proofArm === 'success' ? "(task / 'src/status.txt').write_text('ready\\nowner=tangle\\n')" : ''}
|
|
328
|
+
`
|
|
329
|
+
writeFileSync(path.join(candidateRoot, 'runner.py'), runner)
|
|
330
|
+
chmodSync(path.join(candidateRoot, 'runner.py'), 0o755)
|
|
331
|
+
const repositoryState = deterministicRepository(
|
|
332
|
+
taskRoot,
|
|
333
|
+
path.join(taskDir, 'environment', 'seed', 'src', 'status.txt'),
|
|
334
|
+
)
|
|
335
|
+
|
|
336
|
+
const taskWorkspace = workspaceSnapshot(taskRoot, ['src/status.txt'])
|
|
337
|
+
const candidateWorkspace = workspaceSnapshot(candidateRoot, ['runner.py'])
|
|
338
|
+
const bundleWithoutDigest = {
|
|
339
|
+
kind: 'agent-candidate-bundle' as const,
|
|
340
|
+
digestAlgorithm: 'rfc8785-sha256' as const,
|
|
341
|
+
profile: {
|
|
342
|
+
name: `pier-no-model-runtime-${proofArm}`,
|
|
343
|
+
prompt: {
|
|
344
|
+
instructions: [
|
|
345
|
+
'Edit only the task repository. Follow the exact user instruction and verify the result.',
|
|
346
|
+
],
|
|
347
|
+
},
|
|
348
|
+
model: { default: modelRequest, reasoningEffort: 'xhigh' as const },
|
|
349
|
+
harness: 'codex' as const,
|
|
350
|
+
resources: { failOnError: true as const },
|
|
351
|
+
},
|
|
352
|
+
code: {
|
|
353
|
+
kind: 'no-op' as const,
|
|
354
|
+
reason: 'proposer-no-change' as const,
|
|
355
|
+
repository: {
|
|
356
|
+
kind: 'github' as const,
|
|
357
|
+
owner: 'tangle-network',
|
|
358
|
+
repo: 'agent-bench-pier-fixture',
|
|
359
|
+
},
|
|
360
|
+
baseCommit: repositoryState.commit,
|
|
361
|
+
baseTree: repositoryState.tree,
|
|
362
|
+
},
|
|
363
|
+
execution: {
|
|
364
|
+
harness: 'codex' as const,
|
|
365
|
+
harnessVersion: 'agent-bench-pier/2.0.0',
|
|
366
|
+
launch: {
|
|
367
|
+
kind: 'candidate-entrypoint' as const,
|
|
368
|
+
entrypoint: 'runner.py',
|
|
369
|
+
interpreter: 'python3' as const,
|
|
370
|
+
},
|
|
371
|
+
instructionDelivery: { kind: 'argv-append' as const },
|
|
372
|
+
cwd: { workspace: 'task' as const, path: '.' },
|
|
373
|
+
environment: { kind: 'evaluator-task-container' as const },
|
|
374
|
+
workspace: candidateWorkspace,
|
|
375
|
+
isolation: {
|
|
376
|
+
network: 'disabled' as const,
|
|
377
|
+
remoteIntegrations: 'disabled' as const,
|
|
378
|
+
candidateSecrets: 'disabled' as const,
|
|
379
|
+
},
|
|
380
|
+
},
|
|
381
|
+
memory: { mode: 'disabled' as const },
|
|
382
|
+
}
|
|
383
|
+
const bundle: AgentCandidateBundle = sealAgentCandidateBundle(bundleWithoutDigest)
|
|
384
|
+
const container: ResolvedAgentCandidateContainer = {
|
|
385
|
+
source: 'evaluator-task-container',
|
|
386
|
+
image: fixtureImage,
|
|
387
|
+
indexDigest: identity.indexDigest,
|
|
388
|
+
manifestDigest: identity.manifestDigest,
|
|
389
|
+
platform: { os: 'linux', architecture: 'amd64' },
|
|
390
|
+
}
|
|
391
|
+
const graderBytes = readFileSync(new URL('../src/pier-result-grader.mjs', import.meta.url))
|
|
392
|
+
const { outputArtifacts, graderArtifact } = outputArtifactStore(graderBytes)
|
|
393
|
+
const grader = createPierResultGrader({
|
|
394
|
+
name: 'pier-official-result',
|
|
395
|
+
version: '1.0.0',
|
|
396
|
+
artifact: graderArtifact,
|
|
397
|
+
})
|
|
398
|
+
const executionId = `pier-no-model-${proofArm}-${contextDigest}`
|
|
399
|
+
const benchmarkTask = sealCandidateBenchmarkTask({
|
|
400
|
+
kind: 'agent-candidate-benchmark-task',
|
|
401
|
+
digestAlgorithm: 'rfc8785-sha256',
|
|
402
|
+
benchmark: {
|
|
403
|
+
name: 'pier-runtime-proof',
|
|
404
|
+
version: '1',
|
|
405
|
+
splitDigest: `sha256:${'b'.repeat(64)}`,
|
|
406
|
+
},
|
|
407
|
+
scenario: {
|
|
408
|
+
id: `agent-bench/pier-candidate-no-model-${proofArm}`,
|
|
409
|
+
kind: 'coding',
|
|
410
|
+
scenarioDigest: sha256(Buffer.from(`pier-runtime-proof:${proofArm}`, 'utf8')),
|
|
411
|
+
},
|
|
412
|
+
instruction,
|
|
413
|
+
repository: {
|
|
414
|
+
identity: 'github.com/tangle-network/agent-bench-pier-fixture',
|
|
415
|
+
rootIdentity: 'tangle-network/agent-bench-pier-fixture',
|
|
416
|
+
baseCommit: repositoryState.commit,
|
|
417
|
+
baseTree: repositoryState.tree,
|
|
418
|
+
},
|
|
419
|
+
outcome: { kind: 'workspace' },
|
|
420
|
+
attempt: { maxAttempts: 1, retryPolicy: 'none' },
|
|
421
|
+
model: {
|
|
422
|
+
requested: modelRequest,
|
|
423
|
+
provider: 'openai',
|
|
424
|
+
model: 'gpt-5.4',
|
|
425
|
+
snapshot: 'gpt-5.4-no-model-proof',
|
|
426
|
+
reasoningEffort: 'xhigh',
|
|
427
|
+
},
|
|
428
|
+
grader: {
|
|
429
|
+
name: grader.name,
|
|
430
|
+
version: grader.version,
|
|
431
|
+
format: 'tangle-grader',
|
|
432
|
+
artifact: grader.artifact,
|
|
433
|
+
},
|
|
434
|
+
workspace: taskWorkspace,
|
|
435
|
+
evaluatorTaskContainer: container,
|
|
436
|
+
limits: {
|
|
437
|
+
timeoutMs: 60_000,
|
|
438
|
+
maxSteps: 8,
|
|
439
|
+
maxModelCalls: 0,
|
|
440
|
+
maxInputTokens: 0,
|
|
441
|
+
maxOutputTokens: 0,
|
|
442
|
+
maxCostUsd: 0,
|
|
443
|
+
},
|
|
444
|
+
})
|
|
445
|
+
const benchmark = sealCandidateBenchmarkSuite({
|
|
446
|
+
tasks: [benchmarkTask],
|
|
447
|
+
reps: 1,
|
|
448
|
+
seeds: [42],
|
|
449
|
+
})
|
|
450
|
+
const task: AgentCandidateTaskExecution = {
|
|
451
|
+
executionId,
|
|
452
|
+
runCell: sealCanonical({
|
|
453
|
+
kind: 'agent-candidate-run-cell' as const,
|
|
454
|
+
experimentDigest: sha256(Buffer.from('pier-runtime-proof-experiment', 'utf8')),
|
|
455
|
+
arm: 'candidate' as const,
|
|
456
|
+
bundleDigest: bundle.digest,
|
|
457
|
+
suiteDigest: benchmark.suite.digest,
|
|
458
|
+
taskDigest: benchmarkTask.digest,
|
|
459
|
+
taskIndex: 0,
|
|
460
|
+
repetition: 0,
|
|
461
|
+
seed: 42,
|
|
462
|
+
attempt: 1,
|
|
463
|
+
}),
|
|
464
|
+
benchmarkSuite: benchmark.suite,
|
|
465
|
+
task: benchmarkTask,
|
|
466
|
+
executionRoots: { taskRoot: '/app', candidateRoot: '/opt/tangle-candidate' },
|
|
467
|
+
stagingRoots: { taskRoot, candidateRoot, profileRoot },
|
|
468
|
+
}
|
|
469
|
+
const workspaces = createAgentCandidateWorkspacePort()
|
|
470
|
+
const ports: AgentCandidateExecutionPorts = {
|
|
471
|
+
artifacts: {
|
|
472
|
+
read: async () => {
|
|
473
|
+
throw new Error('the proof uses only embedded artifacts')
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
repositories: { resolve: async () => taskRoot },
|
|
477
|
+
workspaces: {
|
|
478
|
+
materialize: async ({ role, snapshot, archive, destination }) => {
|
|
479
|
+
if (destination === taskRoot || destination === candidateRoot) return
|
|
480
|
+
await workspaces.materialize({
|
|
481
|
+
role,
|
|
482
|
+
snapshot,
|
|
483
|
+
archive,
|
|
484
|
+
destination,
|
|
485
|
+
})
|
|
486
|
+
},
|
|
487
|
+
},
|
|
488
|
+
containers: { resolve: async () => container },
|
|
489
|
+
models: {
|
|
490
|
+
resolve: async ({ requested, reasoningEffort }) => {
|
|
491
|
+
if (!reasoningEffort) throw new Error('resolved model requires reasoning effort')
|
|
492
|
+
return {
|
|
493
|
+
requested,
|
|
494
|
+
provider: 'openai',
|
|
495
|
+
model: 'gpt-5.4',
|
|
496
|
+
snapshot: 'gpt-5.4-no-model-proof',
|
|
497
|
+
reasoningEffort,
|
|
498
|
+
}
|
|
499
|
+
},
|
|
500
|
+
reserveGrant: async ({ limits, preparationId, expiresAtMs }) => ({
|
|
501
|
+
preparationId,
|
|
502
|
+
digest: `sha256:${'c'.repeat(64)}`,
|
|
503
|
+
expiresAtMs,
|
|
504
|
+
enforcedLimits: limits,
|
|
505
|
+
network: { mode: 'disabled' },
|
|
506
|
+
}),
|
|
507
|
+
activateGrant: async () => ({
|
|
508
|
+
env: { MODEL_GATEWAY_TOKEN: 'zero-model-proof' },
|
|
509
|
+
}),
|
|
510
|
+
settleGrant: async ({ preparationId }) => ({
|
|
511
|
+
preparationId,
|
|
512
|
+
grantDigest: `sha256:${'c'.repeat(64)}`,
|
|
513
|
+
closed: true,
|
|
514
|
+
calls: [],
|
|
515
|
+
}),
|
|
516
|
+
},
|
|
517
|
+
memory: {
|
|
518
|
+
reset: async () => {
|
|
519
|
+
throw new Error('disabled memory must not be reset')
|
|
520
|
+
},
|
|
521
|
+
activate: async () => {
|
|
522
|
+
throw new Error('disabled memory must not be activated')
|
|
523
|
+
},
|
|
524
|
+
close: async () => {
|
|
525
|
+
throw new Error('disabled memory must not be closed')
|
|
526
|
+
},
|
|
527
|
+
},
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
const verified = await verifyAgentCandidateBundle(bundle, ports)
|
|
531
|
+
const prepared = await prepareAgentCandidateExecution(verified, task, ports)
|
|
532
|
+
if (prepareOnly) {
|
|
533
|
+
const disposal = await disposePreparedAgentCandidateExecution(prepared)
|
|
534
|
+
if (disposal.disposed !== true) throw new Error('prepared candidate was not disposed')
|
|
535
|
+
process.stdout.write(
|
|
536
|
+
`${JSON.stringify({
|
|
537
|
+
prepared: true,
|
|
538
|
+
disposed: true,
|
|
539
|
+
executionPlanDigest: prepared.executionPlan.value.digest,
|
|
540
|
+
graderDigest: benchmarkTask.grader.artifact.sha256,
|
|
541
|
+
})}\n`,
|
|
542
|
+
)
|
|
543
|
+
} else {
|
|
544
|
+
const traceStore = new InMemoryTraceStore()
|
|
545
|
+
const claimStore = new FileAgentCandidateExecutionClaimStore({
|
|
546
|
+
directory: path.join(scratch, 'claims'),
|
|
547
|
+
})
|
|
548
|
+
let acceptedRewards: { reward: number; patch_applied: number } | undefined
|
|
549
|
+
let acceptedTrialPath: string | undefined
|
|
550
|
+
const jobName = `tangle-runtime-candidate-no-model-${proofArm}`
|
|
551
|
+
const controller = new FilePierCandidateTrialController({
|
|
552
|
+
directory: path.join(scratch, 'trial-control'),
|
|
553
|
+
readResult: async ({ jobsDirectory, jobName }) => {
|
|
554
|
+
const trialResult = findTrialResult(path.join(jobsDirectory, jobName))
|
|
555
|
+
if (!trialResult) return undefined
|
|
556
|
+
return {
|
|
557
|
+
value: trialResult.value,
|
|
558
|
+
resultBytes: readFileSync(trialResult.path),
|
|
559
|
+
taskPatch: readFileSync(
|
|
560
|
+
path.join(path.dirname(trialResult.path), 'artifacts', 'model.patch'),
|
|
561
|
+
),
|
|
562
|
+
}
|
|
563
|
+
},
|
|
564
|
+
launch: (staged, { request }) => {
|
|
565
|
+
const evaluatorArgs = Object.keys(staged.evaluatorEnv).flatMap((name) => [
|
|
566
|
+
'--agent-env',
|
|
567
|
+
`${name}=\${${name}}`,
|
|
568
|
+
])
|
|
569
|
+
return {
|
|
570
|
+
command: 'uv',
|
|
571
|
+
args: [
|
|
572
|
+
'run',
|
|
573
|
+
'pier',
|
|
574
|
+
'run',
|
|
575
|
+
'--path',
|
|
576
|
+
taskDir,
|
|
577
|
+
...staged.agentArgs,
|
|
578
|
+
...staged.attemptArgs,
|
|
579
|
+
...evaluatorArgs,
|
|
580
|
+
'--env',
|
|
581
|
+
'docker',
|
|
582
|
+
'--job-name',
|
|
583
|
+
jobName,
|
|
584
|
+
'--jobs-dir',
|
|
585
|
+
jobsDir,
|
|
586
|
+
'--n-concurrent',
|
|
587
|
+
'1',
|
|
588
|
+
'--agent-timeout-multiplier',
|
|
589
|
+
'2',
|
|
590
|
+
'--quiet',
|
|
591
|
+
],
|
|
592
|
+
cwd: pierRepo,
|
|
593
|
+
env: { ...process.env, PYTHONPATH: benchDir, ...staged.evaluatorEnv },
|
|
594
|
+
jobsDirectory: jobsDir,
|
|
595
|
+
jobName,
|
|
596
|
+
readResult: async () => {
|
|
597
|
+
const trialResult = findTrialResult(jobsDir)
|
|
598
|
+
if (!trialResult) throw new Error(`Pier emitted no trial result under ${jobsDir}`)
|
|
599
|
+
const result = trialResult.value
|
|
600
|
+
if (result.exception_info !== null) {
|
|
601
|
+
throw new Error(
|
|
602
|
+
`Pier trial captured an exception: ${JSON.stringify(result.exception_info)}`,
|
|
603
|
+
)
|
|
604
|
+
}
|
|
605
|
+
const rewards = result.verifier_result?.rewards
|
|
606
|
+
if (
|
|
607
|
+
rewards?.reward !== expectedReward ||
|
|
608
|
+
rewards?.patch_applied !== expectedPatchApplied
|
|
609
|
+
) {
|
|
610
|
+
throw new Error(
|
|
611
|
+
`Pier ${proofArm} control returned unexpected rewards: ${JSON.stringify(rewards)}`,
|
|
612
|
+
)
|
|
613
|
+
}
|
|
614
|
+
const agentResult = result.agent_result
|
|
615
|
+
for (const name of ['n_input_tokens', 'n_cache_tokens', 'n_output_tokens', 'cost_usd']) {
|
|
616
|
+
if (agentResult?.[name] !== null) {
|
|
617
|
+
throw new Error(
|
|
618
|
+
`Pier must not author protected usage ${name}: ${agentResult?.[name]}`,
|
|
619
|
+
)
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
const observedElapsedMs = agentResult?.metadata?.observedElapsedMs
|
|
623
|
+
if (!Number.isInteger(observedElapsedMs) || observedElapsedMs < 0) {
|
|
624
|
+
throw new Error(`Pier omitted protected elapsed time: ${observedElapsedMs}`)
|
|
625
|
+
}
|
|
626
|
+
const endedAt = Date.now()
|
|
627
|
+
await traceStore.appendRun({
|
|
628
|
+
runId: request.trace.runId,
|
|
629
|
+
scenarioId: benchmarkTask.scenario.id,
|
|
630
|
+
startedAt: endedAt - observedElapsedMs,
|
|
631
|
+
endedAt,
|
|
632
|
+
status: 'completed',
|
|
633
|
+
tags: { ...request.trace.tags },
|
|
634
|
+
})
|
|
635
|
+
acceptedRewards = rewards
|
|
636
|
+
acceptedTrialPath = path.relative(jobsDir, trialResult.path)
|
|
637
|
+
return {
|
|
638
|
+
value: result,
|
|
639
|
+
resultBytes: readFileSync(trialResult.path),
|
|
640
|
+
taskPatch: readFileSync(
|
|
641
|
+
path.join(path.dirname(trialResult.path), 'artifacts', 'model.patch'),
|
|
642
|
+
),
|
|
643
|
+
}
|
|
644
|
+
},
|
|
645
|
+
}
|
|
646
|
+
},
|
|
647
|
+
})
|
|
648
|
+
const finalized = await executePreparedPierCandidate({
|
|
649
|
+
prepared,
|
|
650
|
+
directory: path.join(scratch, 'sealed'),
|
|
651
|
+
pierVersion: pinnedPierVersion,
|
|
652
|
+
traceStore,
|
|
653
|
+
claimStore,
|
|
654
|
+
outputArtifacts,
|
|
655
|
+
grader,
|
|
656
|
+
controller,
|
|
657
|
+
})
|
|
658
|
+
if (!finalized.succeeded) {
|
|
659
|
+
throw new Error(`runtime rejected the protected Pier capture: ${finalized.reason}`)
|
|
660
|
+
}
|
|
661
|
+
if (!acceptedRewards || !acceptedTrialPath) {
|
|
662
|
+
throw new Error('atomic Pier executor returned without accepted verifier evidence')
|
|
663
|
+
}
|
|
664
|
+
if (
|
|
665
|
+
finalized.receipt.value.benchmarkResult.material.score !== expectedReward ||
|
|
666
|
+
finalized.receipt.value.benchmarkResult.material.passed !== (expectedReward === 1)
|
|
667
|
+
) {
|
|
668
|
+
throw new Error(
|
|
669
|
+
`runtime receipt rejected the official Pier result: ${JSON.stringify(finalized.receipt.value.benchmarkResult.material)}`,
|
|
670
|
+
)
|
|
671
|
+
}
|
|
672
|
+
assertTreeOmits(scratch, 'zero-model-proof')
|
|
673
|
+
const usage = finalized.receipt.value.usage
|
|
674
|
+
if (
|
|
675
|
+
usage.modelCalls !== 0 ||
|
|
676
|
+
usage.inputTokens !== 0 ||
|
|
677
|
+
usage.outputTokens !== 0 ||
|
|
678
|
+
usage.costUsd !== 0 ||
|
|
679
|
+
finalized.receipt.value.trace.modelCallCount !== 0
|
|
680
|
+
) {
|
|
681
|
+
throw new Error(`runtime minted nonzero usage for a zero-model run: ${JSON.stringify(usage)}`)
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
console.log(
|
|
685
|
+
JSON.stringify(
|
|
686
|
+
{
|
|
687
|
+
arm: proofArm,
|
|
688
|
+
reward: acceptedRewards.reward,
|
|
689
|
+
patchApplied: acceptedRewards.patch_applied,
|
|
690
|
+
modelCalls: usage.modelCalls,
|
|
691
|
+
inputTokens: usage.inputTokens,
|
|
692
|
+
outputTokens: usage.outputTokens,
|
|
693
|
+
costUsd: usage.costUsd,
|
|
694
|
+
pierContextUsage: null,
|
|
695
|
+
profileExcludedByVerifier: true,
|
|
696
|
+
container: {
|
|
697
|
+
image: fixtureImage,
|
|
698
|
+
indexDigest: identity.indexDigest,
|
|
699
|
+
manifestDigest: identity.manifestDigest,
|
|
700
|
+
platform,
|
|
701
|
+
},
|
|
702
|
+
executionPlanDigest: prepared.executionPlan.value.digest,
|
|
703
|
+
materializationReceiptDigest: prepared.materializationReceipt.digest,
|
|
704
|
+
runReceiptDigest: finalized.receipt.digest,
|
|
705
|
+
trial: acceptedTrialPath,
|
|
706
|
+
},
|
|
707
|
+
null,
|
|
708
|
+
2,
|
|
709
|
+
),
|
|
710
|
+
)
|
|
711
|
+
}
|
|
712
|
+
} finally {
|
|
713
|
+
if (process.env.KEEP_PIER_FIXTURE !== '1') rmSync(scratch, { recursive: true, force: true })
|
|
714
|
+
else console.error(`Pier runtime fixture retained at ${scratch}`)
|
|
715
|
+
}
|