@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,321 @@
1
+ """Evaluator-owned process isolation for one Pier candidate invocation."""
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
10
+ from typing import Any, Protocol
11
+
12
+ from pier.environments.base import BaseEnvironment
13
+
14
+ from .candidate_contract import sha256_bytes
15
+
16
+
17
+ class ProcessBoundaryHost(Protocol):
18
+ async def _exec(
19
+ self, environment: BaseEnvironment, command: str, **kwargs: Any
20
+ ) -> Any: ...
21
+
22
+ async def _ensure_real_directory(
23
+ self, environment: BaseEnvironment, path: str, *, anchor: str, mode: int = 0o755
24
+ ) -> None: ...
25
+
26
+ async def _assert_real_directory(
27
+ self,
28
+ environment: BaseEnvironment,
29
+ path: str,
30
+ *,
31
+ label: str,
32
+ user: str | int | None = "root",
33
+ ) -> None: ...
34
+
35
+ async def _write_verified_file(
36
+ self,
37
+ environment: BaseEnvironment,
38
+ source: Path,
39
+ target: str,
40
+ *,
41
+ anchor: str,
42
+ mode: int,
43
+ digest: str,
44
+ byte_length: int,
45
+ ) -> None: ...
46
+
47
+
48
+ @dataclass(frozen=True)
49
+ class ProcessBoundaryConfig:
50
+ uid: int
51
+ gid: int
52
+ evaluator_root: str
53
+ control_root: str
54
+ home: str
55
+ temporary: str
56
+ isolate_user: bool = True
57
+
58
+
59
+ class CandidateProcessBoundary:
60
+ def __init__(self, host: ProcessBoundaryHost, config: ProcessBoundaryConfig):
61
+ self._host = host
62
+ self.config = config
63
+
64
+ async def prepare_identity(
65
+ self, environment: BaseEnvironment, workspace_roots: tuple[str, ...]
66
+ ) -> None:
67
+ config = self.config
68
+ await self._host._ensure_real_directory(
69
+ environment, config.evaluator_root, anchor="/", mode=0o755
70
+ )
71
+ await self._host._exec(
72
+ environment,
73
+ f"chmod 0755 -- {shlex.quote(config.evaluator_root)}",
74
+ user="root",
75
+ )
76
+ for path, mode in (
77
+ (config.control_root, 0o700),
78
+ (config.home, 0o700),
79
+ (config.temporary, 0o700),
80
+ ):
81
+ await self._host._ensure_real_directory(
82
+ environment, path, anchor="/", mode=mode
83
+ )
84
+ await self._host._exec(
85
+ environment,
86
+ f"chmod {mode:o} -- {shlex.quote(path)}",
87
+ user="root",
88
+ )
89
+ if not config.isolate_user:
90
+ return
91
+ await self._host._exec(
92
+ environment,
93
+ "\n".join(
94
+ [
95
+ "set -eu",
96
+ "command -v setsid >/dev/null",
97
+ "command -v setpriv >/dev/null",
98
+ f"! grep -l '^Uid:[[:space:]]*{config.uid}[[:space:]]' "
99
+ "/proc/[0-9]*/status >/dev/null 2>&1",
100
+ f"chown {config.uid}:{config.gid} -- "
101
+ f"{shlex.quote(config.home)} {shlex.quote(config.temporary)}",
102
+ f"chown -R {config.uid}:{config.gid} -- "
103
+ + " ".join(shlex.quote(root) for root in workspace_roots),
104
+ ]
105
+ ),
106
+ user="root",
107
+ )
108
+
109
+ async def stage_wrapper(self, environment: BaseEnvironment) -> tuple[str, str]:
110
+ token = secrets.token_hex(24)
111
+ wrapper = f"{self.config.control_root}/run-{token}.sh"
112
+ marker = f"{self.config.control_root}/timeout-{token}"
113
+ raw = self._runner_script()
114
+ with tempfile.NamedTemporaryFile(delete=False) as handle:
115
+ handle.write(raw)
116
+ local_path = Path(handle.name)
117
+ try:
118
+ await self._host._write_verified_file(
119
+ environment,
120
+ local_path,
121
+ wrapper,
122
+ anchor=self.config.control_root,
123
+ mode=0o700,
124
+ digest=sha256_bytes(raw),
125
+ byte_length=len(raw),
126
+ )
127
+ finally:
128
+ local_path.unlink(missing_ok=True)
129
+ return wrapper, marker
130
+
131
+ async def kill_and_wait(self, environment: BaseEnvironment) -> None:
132
+ """Kill every process in the candidate identity and prove none remain."""
133
+ if not self.config.isolate_user:
134
+ return
135
+ command = """set -eu
136
+ candidate_pids() {
137
+ for status in /proc/[0-9]*/status; do
138
+ test -r "$status" || continue
139
+ pid=${status#/proc/}
140
+ pid=${pid%/status}
141
+ while IFS=: read -r key value; do
142
+ if test "$key" = Uid; then
143
+ set -- $value
144
+ if test "${1:-}" = "$TARGET_UID"; then
145
+ printf '%s\n' "$pid"
146
+ fi
147
+ break
148
+ fi
149
+ done < "$status"
150
+ done
151
+ }
152
+
153
+ for attempt in $(seq 1 100); do
154
+ pids=$(candidate_pids)
155
+ test -n "$pids" || exit 0
156
+ for pid in $pids; do
157
+ kill -KILL "$pid" 2>/dev/null || true
158
+ done
159
+ sleep 0.02
160
+ done
161
+ remaining=$(candidate_pids)
162
+ test -z "$remaining" || {
163
+ printf 'candidate processes survived SIGKILL: %s\n' "$remaining" >&2
164
+ exit 1
165
+ }
166
+ """
167
+ await self._host._exec(
168
+ environment,
169
+ command,
170
+ env={"TARGET_UID": str(self.config.uid)},
171
+ user="root",
172
+ timeout_sec=5,
173
+ )
174
+
175
+ async def remove_control_files(
176
+ self,
177
+ environment: BaseEnvironment,
178
+ wrapper: str | None,
179
+ marker: str | None,
180
+ ) -> None:
181
+ paths = [path for path in (wrapper, marker) if path is not None]
182
+ if not paths:
183
+ return
184
+ await self._host._assert_real_directory(
185
+ environment,
186
+ self.config.control_root,
187
+ label="candidate control directory",
188
+ )
189
+ await self._host._exec(
190
+ environment,
191
+ "rm -f -- " + " ".join(shlex.quote(path) for path in paths),
192
+ user="root",
193
+ )
194
+
195
+ async def timeout_marker_exists(
196
+ self, environment: BaseEnvironment, marker: str
197
+ ) -> bool:
198
+ quoted = shlex.quote(marker)
199
+ result = await self._host._exec(
200
+ environment,
201
+ f'test -f {quoted} && test ! -L {quoted} && test "$(cat -- {quoted})" = timeout',
202
+ user="root",
203
+ check=False,
204
+ )
205
+ return result.return_code == 0
206
+
207
+ def _runner_script(self) -> bytes:
208
+ if not self.config.isolate_user:
209
+ return b"""#!/bin/sh
210
+ set -eu
211
+ marker=$1
212
+ uid=$2
213
+ gid=$3
214
+ deadline=$4
215
+ grace=$5
216
+ stdin_path=$6
217
+ shift 6
218
+ rm -f -- "$marker" "$marker.tmp"
219
+ set +e
220
+ if test "$stdin_path" = -; then
221
+ timeout --signal=TERM --kill-after="${grace}s" "${deadline}s" env "$@"
222
+ else
223
+ timeout --signal=TERM --kill-after="${grace}s" "${deadline}s" env "$@" < "$stdin_path"
224
+ fi
225
+ status=$?
226
+ set -e
227
+ if test "$status" = 124; then
228
+ printf timeout > "$marker"
229
+ fi
230
+ exit "$status"
231
+ """
232
+ return b"""#!/bin/sh
233
+ set -eu
234
+ marker=$1
235
+ uid=$2
236
+ gid=$3
237
+ deadline=$4
238
+ grace=$5
239
+ stdin_path=$6
240
+ shift 6
241
+ rm -f -- "$marker" "$marker.tmp"
242
+
243
+ kill_candidate_uid() {
244
+ signal=$1
245
+ for status in /proc/[0-9]*/status; do
246
+ test -r "$status" || continue
247
+ pid=${status#/proc/}
248
+ pid=${pid%/status}
249
+ while IFS=: read -r key value; do
250
+ if test "$key" = Uid; then
251
+ set -- $value
252
+ if test "${1:-}" = "$uid"; then
253
+ kill "-$signal" "$pid" 2>/dev/null || true
254
+ fi
255
+ break
256
+ fi
257
+ done < "$status"
258
+ done
259
+ }
260
+
261
+ candidate_uid_is_dead() {
262
+ for status in /proc/[0-9]*/status; do
263
+ test -r "$status" || continue
264
+ while IFS=: read -r key value; do
265
+ if test "$key" = Uid; then
266
+ set -- $value
267
+ test "${1:-}" = "$uid" && return 1
268
+ break
269
+ fi
270
+ done < "$status"
271
+ done
272
+ return 0
273
+ }
274
+
275
+ kill_and_wait_candidate_uid() {
276
+ kill_candidate_uid KILL
277
+ attempt=0
278
+ while ! candidate_uid_is_dead; do
279
+ attempt=$((attempt + 1))
280
+ test "$attempt" -lt 100 || {
281
+ printf 'candidate processes survived SIGKILL\n' >&2
282
+ return 1
283
+ }
284
+ kill_candidate_uid KILL
285
+ sleep 0.02
286
+ done
287
+ }
288
+
289
+ if test "$stdin_path" = -; then
290
+ setsid setpriv --reuid="$uid" --regid="$gid" --clear-groups --no-new-privs \
291
+ --bounding-set=-all --inh-caps=-all --ambient-caps=-all --pdeathsig=KILL -- env "$@" &
292
+ else
293
+ setsid setpriv --reuid="$uid" --regid="$gid" --clear-groups --no-new-privs \
294
+ --bounding-set=-all --inh-caps=-all --ambient-caps=-all --pdeathsig=KILL -- env "$@" < "$stdin_path" &
295
+ fi
296
+ candidate_pid=$!
297
+ (
298
+ sleep "$deadline"
299
+ if kill -0 "$candidate_pid" 2>/dev/null; then
300
+ umask 077
301
+ printf timeout > "$marker.tmp"
302
+ mv -fT -- "$marker.tmp" "$marker"
303
+ kill_candidate_uid TERM
304
+ sleep "$grace"
305
+ kill_and_wait_candidate_uid
306
+ fi
307
+ ) &
308
+ watchdog_pid=$!
309
+
310
+ set +e
311
+ wait "$candidate_pid"
312
+ candidate_status=$?
313
+ set -e
314
+ kill "$watchdog_pid" 2>/dev/null || true
315
+ wait "$watchdog_pid" 2>/dev/null || true
316
+ kill_and_wait_candidate_uid
317
+ if test -f "$marker"; then
318
+ exit 124
319
+ fi
320
+ exit "$candidate_status"
321
+ """