@tangle-network/agent-bench 0.1.0 → 0.3.5

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 (139) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/HARNESS.md +302 -0
  3. package/README.md +26 -1
  4. package/fixtures/aec-bench.json +18 -0
  5. package/fixtures/agentbench-dbbench.json +22 -0
  6. package/fixtures/bfcl.json +45 -0
  7. package/fixtures/commit0.json +72 -0
  8. package/fixtures/crag.json +10 -0
  9. package/fixtures/dabstep.json +22 -0
  10. package/fixtures/enterpriseops-gym.json +103 -0
  11. package/fixtures/finresearchbench.json +21 -0
  12. package/fixtures/finsearchcomp.json +66 -0
  13. package/fixtures/frames.json +26 -0
  14. package/fixtures/hotpotqa.json +182 -0
  15. package/fixtures/nomiracl.json +26 -0
  16. package/fixtures/open-rag-bench.json +16 -0
  17. package/fixtures/pier-agent/no-model-task/environment/Dockerfile +16 -0
  18. package/fixtures/pier-agent/no-model-task/environment/seed/src/status.txt +1 -0
  19. package/fixtures/pier-agent/no-model-task/instruction.md +6 -0
  20. package/fixtures/pier-agent/no-model-task/pre_artifacts.sh +6 -0
  21. package/fixtures/pier-agent/no-model-task/task.toml +35 -0
  22. package/fixtures/pier-agent/no-model-task/tests/Dockerfile +17 -0
  23. package/fixtures/pier-agent/no-model-task/tests/seed/src/status.txt +1 -0
  24. package/fixtures/pier-agent/no-model-task/tests/test.sh +19 -0
  25. package/fixtures/programbench.json +17 -0
  26. package/fixtures/ragbench.json +21 -0
  27. package/fixtures/simpleqa.json +121 -0
  28. package/fixtures/t2-ragbench.json +13 -0
  29. package/fixtures/tau2-bench.json +16 -0
  30. package/fixtures/tau3-banking.json +16 -0
  31. package/fixtures/toollm.json +28 -0
  32. package/fixtures/webarena-verified.json +20 -0
  33. package/package.json +39 -15
  34. package/pier_agents/__init__.py +18 -0
  35. package/pier_agents/candidate_contract.py +755 -0
  36. package/pier_agents/process_boundary.py +321 -0
  37. package/pier_agents/tangle_candidate.py +907 -0
  38. package/pier_agents/workspace_boundary.py +368 -0
  39. package/scripts/appworld_driver.py +359 -0
  40. package/scripts/cadbench_prepare.py +22 -0
  41. package/scripts/cadgenbench_hard_parts.py +48 -0
  42. package/scripts/clbench_codebase_judge.py +73 -0
  43. package/scripts/commit0_judge.py +170 -0
  44. package/scripts/dabstep_judge.py +42 -0
  45. package/scripts/enterpriseops_gym_judge.py +281 -0
  46. package/scripts/programbench_judge.py +120 -0
  47. package/scripts/render-gate-chart.mjs +176 -0
  48. package/scripts/run-package-tests.mjs +56 -0
  49. package/scripts/terminate-pier-trial.mts +66 -0
  50. package/scripts/trata-hedge/README.md +56 -0
  51. package/scripts/trata-hedge/run.sh +60 -0
  52. package/scripts/trata-hedge/solve.py +83 -0
  53. package/scripts/verify-packed-consumer.mjs +224 -0
  54. package/scripts/verify-pier-agent.mts +715 -0
  55. package/scripts/verify-pier-pair.mts +74 -0
  56. package/scripts/verify-pier-recovery.mts +139 -0
  57. package/src/adapters.ts +26 -0
  58. package/src/benchmarks/_harness.test.mts +178 -0
  59. package/src/benchmarks/_harness.ts +239 -16
  60. package/src/benchmarks/agentbench.ts +163 -0
  61. package/src/benchmarks/appworld.test.mts +15 -9
  62. package/src/benchmarks/bfcl.ts +346 -0
  63. package/src/benchmarks/crag.ts +137 -0
  64. package/src/benchmarks/dabstep.test.mts +70 -0
  65. package/src/benchmarks/dabstep.ts +212 -0
  66. package/src/benchmarks/external-adapters.test.mts +150 -0
  67. package/src/benchmarks/finresearchbench.ts +269 -0
  68. package/src/benchmarks/humaneval.ts +20 -8
  69. package/src/benchmarks/nomiracl.ts +180 -0
  70. package/src/benchmarks/open-rag-bench.ts +153 -0
  71. package/src/benchmarks/rag-benchmarks.test.mts +138 -0
  72. package/src/benchmarks/rag-shared.ts +327 -0
  73. package/src/benchmarks/ragbench.ts +171 -0
  74. package/src/benchmarks/swe-bench.test.mts +61 -0
  75. package/src/benchmarks/swe-bench.ts +201 -19
  76. package/src/benchmarks/t2-ragbench.ts +166 -0
  77. package/src/benchmarks/tau-bench-shared.ts +214 -0
  78. package/src/benchmarks/tau2-bench.ts +30 -0
  79. package/src/benchmarks/tau3-banking.ts +29 -0
  80. package/src/benchmarks/terminal-bench.test.mts +33 -0
  81. package/src/benchmarks/terminal-bench.ts +23 -8
  82. package/src/benchmarks/toollm.ts +254 -0
  83. package/src/benchmarks/types.ts +42 -0
  84. package/src/benchmarks/webarena-verified.ts +200 -0
  85. package/src/commit0-prereqs.sh +0 -0
  86. package/src/coordination-mcp-container-reach.mts +181 -0
  87. package/src/decoder-live.mts +1 -1
  88. package/src/examples/README.md +103 -39
  89. package/src/examples/benchmark-matrix.mts +101 -0
  90. package/src/examples/lean-proof-gate.README.md +77 -0
  91. package/src/examples/lean-proof-gate.mts +162 -0
  92. package/src/examples/lean-verify.ts +95 -0
  93. package/src/examples/lean.Dockerfile +12 -0
  94. package/src/examples/math-demo.mts +9 -7
  95. package/src/examples/strategy-demo.mts +10 -12
  96. package/src/gate.ts +3 -2
  97. package/src/hev-eval.mts +69 -0
  98. package/src/hev-improve.mts +169 -0
  99. package/src/hev-structural.mts +688 -0
  100. package/src/index.ts +73 -0
  101. package/src/mbpp-structural.mts +662 -0
  102. package/src/pier-agent.test-fixtures.mts +19 -0
  103. package/src/pier-agent.test.mts +363 -0
  104. package/src/pier-agent.ts +657 -0
  105. package/src/pier-result-grader.mjs +30 -0
  106. package/src/pier-result-grader.test.mts +62 -0
  107. package/src/pier-result-grader.ts +108 -0
  108. package/src/pier-task-outcome.test.mts +117 -0
  109. package/src/pier-task-outcome.ts +240 -0
  110. package/src/pier-trial-controller.test.mts +412 -0
  111. package/src/pier-trial-controller.ts +858 -0
  112. package/src/pier-trial-supervisor.mjs +352 -0
  113. package/src/resolve-client.ts +25 -2
  114. package/src/run-benchmarks-cli.mts +72 -0
  115. package/src/run-benchmarks-report.ts +66 -0
  116. package/src/run-benchmarks.test.mts +231 -0
  117. package/src/run-benchmarks.ts +589 -0
  118. package/src/smoke-structural-rollout.mts +393 -0
  119. package/src/swe-bench-env.test.ts +207 -0
  120. package/src/swe-bench-env.ts +554 -0
  121. package/src/swe-jail.ts +293 -0
  122. package/src/swe-self-improve.mts +84 -0
  123. package/src/swe-structural-judge-policy.test.ts +117 -0
  124. package/src/swe-structural-judge-policy.ts +133 -0
  125. package/src/swe-structural-policy.test.ts +124 -0
  126. package/src/swe-structural-policy.ts +132 -0
  127. package/src/swe-structural-provenance.test.ts +93 -0
  128. package/src/swe-structural-provenance.ts +138 -0
  129. package/src/swe-structural.mts +1260 -0
  130. package/src/swe-temp.ts +14 -0
  131. package/src/tb-container-executor.mts +234 -0
  132. package/src/tb-container-executor.test.mts +99 -0
  133. package/src/tb-supervisor-sidecar.mts +222 -0
  134. package/src/trata-gepa.mts +1 -1
  135. package/steerers/eops-itsm-population.json +1 -0
  136. package/tb_agents/opencode_refine_agent.py +117 -0
  137. package/tb_agents/opencode_router_agent.py +406 -0
  138. package/tb_agents/opencode_supervisor_agent.py +239 -0
  139. package/tb_agents/script_agent.py +66 -0
@@ -0,0 +1,368 @@
1
+ """Verify and materialize runtime-signed workspaces inside a Pier container."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import secrets
6
+ import shlex
7
+ import tempfile
8
+ from dataclasses import dataclass
9
+ from pathlib import Path, PurePosixPath
10
+ from typing import Any, Protocol
11
+
12
+ from pier.environments.base import BaseEnvironment
13
+
14
+ from .candidate_contract import (
15
+ PreparedCandidateContract,
16
+ WorkspaceFile,
17
+ sha256_bytes,
18
+ )
19
+
20
+
21
+ def _workspace_check_script(
22
+ root: str,
23
+ files: tuple[WorkspaceFile, ...],
24
+ *,
25
+ allow_task_metadata: bool,
26
+ ) -> bytes:
27
+ quoted_root = shlex.quote(root)
28
+ prune = (
29
+ f"\\( -path {shlex.quote(root + '/.git')} -o "
30
+ f"-path {shlex.quote(root + '/.sidecar')} \\) -prune -o "
31
+ if allow_task_metadata
32
+ else ""
33
+ )
34
+ expected_args = " ".join(shlex.quote(file.path) for file in files)
35
+ expected = (
36
+ f"$(printf '%s\\n' {expected_args} | LC_ALL=C sort)" if files else "''"
37
+ )
38
+ checks = [
39
+ "#!/bin/sh",
40
+ "set -eu",
41
+ f"test -d {quoted_root}",
42
+ f"test ! -L {quoted_root}",
43
+ f'test "$(realpath -e -- {quoted_root})" = {quoted_root}',
44
+ f'test -z "$(find {quoted_root} {prune}-type l -print -quit)"',
45
+ f'test -z "$(find {quoted_root} {prune}! -type d ! -type f -print -quit)"',
46
+ f"observed=$(find {quoted_root} {prune}-type f -printf '%P\\n' | LC_ALL=C sort)",
47
+ f"expected={expected}",
48
+ 'test "$observed" = "$expected"',
49
+ ]
50
+ for file in files:
51
+ path = shlex.quote(f"{root}/{file.path}")
52
+ checks.extend(
53
+ [
54
+ f"test -f {path}",
55
+ f"test ! -L {path}",
56
+ f'test "$(stat -c %h -- {path})" = 1',
57
+ f'test "$(stat -c %a -- {path})" = {file.mode:o}',
58
+ f'test "$(wc -c < {path})" = {file.byte_length}',
59
+ f"test \"$(sha256sum -- {path} | cut -d' ' -f1)\" = "
60
+ f"{file.sha256.removeprefix('sha256:')}",
61
+ ]
62
+ )
63
+ return ("\n".join(checks) + "\n").encode("utf-8")
64
+
65
+
66
+ class WorkspaceBoundaryHost(Protocol):
67
+ async def _exec(
68
+ self, environment: BaseEnvironment, command: str, **kwargs: Any
69
+ ) -> Any: ...
70
+
71
+ async def _ensure_real_directory(
72
+ self,
73
+ environment: BaseEnvironment,
74
+ path: str,
75
+ *,
76
+ anchor: str,
77
+ mode: int = 0o755,
78
+ ) -> None: ...
79
+
80
+ async def _assert_real_directory(
81
+ self,
82
+ environment: BaseEnvironment,
83
+ path: str,
84
+ *,
85
+ label: str,
86
+ user: str | int | None = "root",
87
+ ) -> None: ...
88
+
89
+ async def _write_verified_file(
90
+ self,
91
+ environment: BaseEnvironment,
92
+ source: Path,
93
+ target: str,
94
+ *,
95
+ anchor: str,
96
+ mode: int,
97
+ digest: str,
98
+ byte_length: int,
99
+ ) -> None: ...
100
+
101
+
102
+ @dataclass(frozen=True)
103
+ class WorkspaceBoundaryConfig:
104
+ contract: PreparedCandidateContract
105
+ task_snapshot: Path
106
+ control_root: str
107
+ protected_roots: tuple[str, ...]
108
+ error_type: type[Exception]
109
+
110
+
111
+ def candidate_git_env(task_root: str) -> dict[str, str]:
112
+ return {
113
+ "GIT_CONFIG_COUNT": "1",
114
+ "GIT_CONFIG_KEY_0": "safe.directory",
115
+ "GIT_CONFIG_VALUE_0": task_root,
116
+ "GIT_CONFIG_NOSYSTEM": "1",
117
+ "GIT_CONFIG_GLOBAL": "/dev/null",
118
+ "GIT_CONFIG_SYSTEM": "/dev/null",
119
+ "GIT_NO_REPLACE_OBJECTS": "1",
120
+ "GIT_TERMINAL_PROMPT": "0",
121
+ "LC_ALL": "C",
122
+ }
123
+
124
+
125
+ class CandidateWorkspaceBoundary:
126
+ def __init__(self, host: WorkspaceBoundaryHost, config: WorkspaceBoundaryConfig):
127
+ self._host = host
128
+ self._config = config
129
+
130
+ @property
131
+ def _contract(self) -> PreparedCandidateContract:
132
+ return self._config.contract
133
+
134
+ def _error(self, message: str) -> Exception:
135
+ return self._config.error_type(message)
136
+
137
+ async def verify_repository(self, environment: BaseEnvironment) -> None:
138
+ root = shlex.quote(self._contract.task_root)
139
+ git = f"git -c core.hooksPath=/dev/null -C {root}"
140
+ env = candidate_git_env(self._contract.task_root)
141
+ head = await self._host._exec(environment, f"{git} rev-parse HEAD", env=env)
142
+ tree = await self._host._exec(
143
+ environment, f"{git} rev-parse 'HEAD^{{tree}}'", env=env
144
+ )
145
+ replacements = await self._host._exec(
146
+ environment,
147
+ f"{git} for-each-ref --format='%(refname)' refs/replace",
148
+ env=env,
149
+ )
150
+ if (head.stdout or "").strip() != self._contract.repository_base_commit:
151
+ raise self._error("task checkout HEAD does not match the signed base commit")
152
+ if (tree.stdout or "").strip() != self._contract.repository_base_tree:
153
+ raise self._error("task checkout tree does not match the signed base tree")
154
+ if (replacements.stdout or "").strip():
155
+ raise self._error("task checkout contains forbidden Git replace refs")
156
+
157
+ async def materialize_task_workspace(self, environment: BaseEnvironment) -> None:
158
+ root = self._contract.task_root
159
+ quoted = shlex.quote(root)
160
+ exists = await self._host._exec(
161
+ environment,
162
+ f"test -e {quoted} || test -L {quoted}",
163
+ user="root",
164
+ check=False,
165
+ )
166
+ if exists.return_code == 0:
167
+ return
168
+ if exists.return_code != 1:
169
+ raise self._error("could not inspect the signed task root")
170
+
171
+ parent = str(PurePosixPath(root).parent)
172
+ await self._host._ensure_real_directory(environment, parent, anchor="/")
173
+ await self._host._exec(
174
+ environment,
175
+ "\n".join(
176
+ [
177
+ "set -eu",
178
+ f"test ! -e {quoted}",
179
+ f"test ! -L {quoted}",
180
+ f"mkdir -- {quoted}",
181
+ f'test "$(realpath -e -- {quoted})" = {quoted}',
182
+ ]
183
+ ),
184
+ user="root",
185
+ )
186
+ await environment.upload_dir(self._config.task_snapshot, root)
187
+ git = f"git -c core.hooksPath=/dev/null -C {quoted}"
188
+ await self._host._exec(
189
+ environment,
190
+ "\n".join(
191
+ [
192
+ "set -eu",
193
+ f"{git} init -b main",
194
+ f"{git} config user.email fixture@tangle.tools",
195
+ f'{git} config user.name "Tangle Fixture"',
196
+ f"{git} add -A",
197
+ f"GIT_AUTHOR_DATE=2000-01-01T00:00:00Z "
198
+ f"GIT_COMMITTER_DATE=2000-01-01T00:00:00Z "
199
+ f"{git} commit -m baseline",
200
+ f"{git} tag benchmark-base",
201
+ ]
202
+ ),
203
+ env=candidate_git_env(root),
204
+ user="root",
205
+ )
206
+
207
+ async def verify_pier_execution_identity(
208
+ self, environment: BaseEnvironment
209
+ ) -> None:
210
+ expected = self._contract.container
211
+ configured_image = getattr(environment.task_env_config, "docker_image", None)
212
+ pinned_image = f"{expected['image']}@{expected['indexDigest']}"
213
+ if configured_image != pinned_image:
214
+ raise self._error(
215
+ "Pier task image does not match the signed immutable image: "
216
+ f"expected={pinned_image} observed={configured_image}"
217
+ )
218
+ configured_os = getattr(environment.task_env_config, "os", None)
219
+ configured_os = getattr(configured_os, "value", configured_os)
220
+ if configured_os is not None and str(configured_os).lower() != "linux":
221
+ raise self._error(
222
+ f"Pier task OS does not match signed Linux platform: {configured_os}"
223
+ )
224
+ platform = expected["platform"]
225
+ observed = await self._host._exec(
226
+ environment,
227
+ 'printf \'%s %s\' "$(uname -s)" "$(uname -m)"',
228
+ user="root",
229
+ )
230
+ kernel, _, machine = (observed.stdout or "").strip().partition(" ")
231
+ architectures = {"x86_64": "amd64", "aarch64": "arm64"}
232
+ if kernel != "Linux" or architectures.get(machine) != platform["architecture"]:
233
+ raise self._error(
234
+ "running Pier platform does not match the signed container platform: "
235
+ f"observed={kernel}/{machine} expected=linux/{platform['architecture']}"
236
+ )
237
+
238
+ async def verify_resolved_root_isolation(
239
+ self, environment: BaseEnvironment
240
+ ) -> None:
241
+ roots = [self._contract.task_root]
242
+ if self._contract.candidate_root is not None:
243
+ roots.append(self._contract.candidate_root)
244
+ for root in roots:
245
+ await self._host._assert_real_directory(
246
+ environment, root, label="execution workspace"
247
+ )
248
+ if self._contract.candidate_root is not None:
249
+ task = shlex.quote(self._contract.task_root)
250
+ candidate = shlex.quote(self._contract.candidate_root)
251
+ await self._host._exec(
252
+ environment,
253
+ "\n".join(
254
+ [
255
+ "set -eu",
256
+ f"task=$(realpath -e -- {task})",
257
+ f"candidate=$(realpath -e -- {candidate})",
258
+ 'test "$task" != "$candidate"',
259
+ 'case "$task" in "$candidate"/*) exit 1;; esac',
260
+ 'case "$candidate" in "$task"/*) exit 1;; esac',
261
+ ]
262
+ ),
263
+ user="root",
264
+ )
265
+ for protected in self._config.protected_roots:
266
+ quoted_protected = shlex.quote(protected)
267
+ for root in roots:
268
+ quoted_root = shlex.quote(root)
269
+ await self._host._exec(
270
+ environment,
271
+ "\n".join(
272
+ [
273
+ "set -eu",
274
+ f"if test -e {quoted_protected}; then",
275
+ f" protected=$(realpath -e -- {quoted_protected})",
276
+ f" root=$(realpath -e -- {quoted_root})",
277
+ ' test "$root" != "$protected"',
278
+ ' case "$root" in "$protected"/*) exit 1;; esac',
279
+ ' case "$protected" in "$root"/*) exit 1;; esac',
280
+ "fi",
281
+ ]
282
+ ),
283
+ user="root",
284
+ )
285
+
286
+ async def verify_container_workspace(
287
+ self,
288
+ environment: BaseEnvironment,
289
+ root: str,
290
+ files: tuple[WorkspaceFile, ...],
291
+ *,
292
+ allow_task_metadata: bool,
293
+ ) -> None:
294
+ script = _workspace_check_script(
295
+ root,
296
+ files,
297
+ allow_task_metadata=allow_task_metadata,
298
+ )
299
+ control_root = self._config.control_root
300
+ target = f"{control_root}/workspace-check-{secrets.token_hex(24)}.sh"
301
+ with tempfile.NamedTemporaryFile(delete=False) as handle:
302
+ handle.write(script)
303
+ local_path = Path(handle.name)
304
+ control_ready = False
305
+
306
+ async def cleanup() -> None:
307
+ local_path.unlink(missing_ok=True)
308
+ if not control_ready:
309
+ return
310
+ await self._host._assert_real_directory(
311
+ environment,
312
+ control_root,
313
+ label="candidate control directory",
314
+ )
315
+ await self._host._exec(
316
+ environment,
317
+ f"rm -f -- {shlex.quote(target)}",
318
+ user="root",
319
+ )
320
+ await self._host._exec(
321
+ environment,
322
+ "\n".join(
323
+ [
324
+ "set -eu",
325
+ f"test ! -e {shlex.quote(target)}",
326
+ f"test ! -L {shlex.quote(target)}",
327
+ f'test -z "$(find {shlex.quote(control_root)} -maxdepth 1 '
328
+ "-name '.tangle-*' -print -quit)\"",
329
+ ]
330
+ ),
331
+ user="root",
332
+ )
333
+
334
+ try:
335
+ await self._host._ensure_real_directory(
336
+ environment,
337
+ control_root,
338
+ anchor="/",
339
+ mode=0o700,
340
+ )
341
+ control_ready = True
342
+ await self._host._exec(
343
+ environment,
344
+ f"chmod 0700 -- {shlex.quote(control_root)}",
345
+ user="root",
346
+ )
347
+ await self._host._write_verified_file(
348
+ environment,
349
+ local_path,
350
+ target,
351
+ anchor=control_root,
352
+ mode=0o600,
353
+ digest=sha256_bytes(script),
354
+ byte_length=len(script),
355
+ )
356
+ await self._host._exec(
357
+ environment,
358
+ f"/bin/sh {shlex.quote(target)}",
359
+ user="root",
360
+ )
361
+ except BaseException as primary_error:
362
+ try:
363
+ await cleanup()
364
+ except BaseException as cleanup_error:
365
+ primary_error.add_note(f"workspace check cleanup failed: {cleanup_error}")
366
+ raise
367
+ else:
368
+ await cleanup()