verifiers 0.2.2.dev40__py3-none-any.whl → 0.2.2.dev42__py3-none-any.whl

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.
verifiers/v1/harness.py CHANGED
@@ -9,7 +9,7 @@ from typing import TYPE_CHECKING, ClassVar, Generic, TypeVar
9
9
  from verifiers.v1.clients import ModelContext
10
10
  from verifiers.v1.configs.harness import HarnessConfig
11
11
  from verifiers.v1.decorators import discover_decorated, invoke_all
12
- from verifiers.v1.errors import HarnessError, boundary
12
+ from verifiers.v1.errors import HarnessError, SandboxError, boundary
13
13
  from verifiers.v1.runtimes import ProgramResult, Runtime
14
14
  from verifiers.v1.task import TaskData
15
15
  from verifiers.v1.types import Messages
@@ -140,6 +140,11 @@ class Harness(ABC, Generic[ConfigT]):
140
140
  if result.exit_code != 0:
141
141
  # The real cause is at the END of a traceback, so keep the tail.
142
142
  detail = (result.stderr or result.stdout).strip()[-2000:] or "<no output>"
143
+ if not await runtime.alive():
144
+ raise SandboxError(
145
+ f"runtime died under harness {self.config.id!r} "
146
+ f"(exit {result.exit_code}): {detail}"
147
+ )
143
148
  raise HarnessError(
144
149
  f"harness {self.config.id!r} exited {result.exit_code}: {detail}"
145
150
  )
@@ -13,7 +13,7 @@ logger = logging.getLogger(__name__)
13
13
 
14
14
 
15
15
  class Terminus2HarnessConfig(HarnessConfig):
16
- version: str = "0.14.0"
16
+ version: str = "0.20.0"
17
17
  """Harbor release to install, pinned for reproducibility."""
18
18
 
19
19
 
@@ -197,6 +197,16 @@ class Runtime(ABC):
197
197
  async def run(self, argv: list[str], env: dict[str, str]) -> ProgramResult:
198
198
  pass
199
199
 
200
+ async def alive(self) -> bool:
201
+ """Whether the box still executes anything. Not every runtime raises when
202
+ the box is gone — some surface it as `exec`'s own non-zero result,
203
+ indistinguishable from the command failing. One probe on the failure path
204
+ tells the two apart before we blame anyone."""
205
+ try:
206
+ return (await self.run(["true"], {})).exit_code == 0
207
+ except Exception: # noqa: BLE001 - failing to exec at all means the box is gone
208
+ return False
209
+
200
210
  async def run_program(self, argv: list[str], env: dict[str, str]) -> ProgramResult:
201
211
  """Run the harness's MAIN program — the rollout itself (a possibly long-lived, stateful,
202
212
  agentic run) — as opposed to the short idempotent infra ops (write / mv / install /
@@ -17,7 +17,6 @@ import subprocess
17
17
  import sys
18
18
  import tarfile
19
19
  import tempfile
20
- import tomllib
21
20
  from collections.abc import Iterator
22
21
  from functools import lru_cache
23
22
  from pathlib import Path
@@ -214,7 +213,7 @@ def dataset_dir(config: HarborConfig) -> Path:
214
213
 
215
214
  def resolve_image(
216
215
  task_dir: Path,
217
- config: dict,
216
+ image: str | None,
218
217
  require_image: bool,
219
218
  ignore_dockerfile: bool = False,
220
219
  ) -> str | None:
@@ -224,9 +223,8 @@ def resolve_image(
224
223
  fallback for tasks with no environment, but would score a Dockerfile task in
225
224
  the wrong environment unless the user explicitly opts in.
226
225
  """
227
- declared = config.get("environment", {}).get("docker_image")
228
- if declared:
229
- return declared
226
+ if image:
227
+ return image
230
228
  if (task_dir / "environment" / "Dockerfile").exists():
231
229
  if ignore_dockerfile:
232
230
  return None
@@ -243,67 +241,49 @@ def resolve_image(
243
241
  return None
244
242
 
245
243
 
246
- def size_to_mb(size: str | float) -> float:
247
- """A Harbor size in MB, from either schema: current integer-MB fields or the
248
- legacy schema-1.0 size strings ("8G", "512M", "64K")."""
249
- if not isinstance(size, str):
250
- return float(size)
251
- scale = {"G": 1024.0, "M": 1.0, "K": 1 / 1024}.get(size.strip().upper()[-1:])
252
- if scale is None:
253
- raise ValueError(
254
- f"invalid Harbor size {size!r}: expected a number of MB or a "
255
- "'<number>[G|M|K]' string"
256
- )
257
- return float(size.strip()[:-1]) * scale
258
-
259
-
260
- def parse_resources(env: dict, multiplier: float = 1.0) -> TaskResources:
261
- # Harbor's current schema reports memory/storage as integer-MB fields; the
262
- # legacy schema 1.0 used size strings under `memory`/`storage`, which Harbor
263
- # still migrates (datasets like senior-swe-bench are authored against it).
264
- # TaskResources stores GB. A zero GPU count means no GPU request rather than
265
- # the string "0".
266
- memory = env.get("memory_mb") or env.get("memory")
267
- disk = env.get("storage_mb") or env.get("storage")
268
- return TaskResources(
269
- cpu=env["cpus"] * multiplier if env.get("cpus") else None,
270
- memory=size_to_mb(memory) / 1024 * multiplier if memory else None,
271
- gpu=str(env["gpus"]) if env.get("gpus") else None,
272
- disk=size_to_mb(disk) / 1024 * multiplier if disk else None,
273
- )
274
-
275
-
276
244
  def parse_task(task_dir: Path, idx: int, harbor_config: HarborConfig) -> HarborData:
277
- # Harbor is optional, so importing its schema is deferred until a Harbor task loads.
245
+ # Harbor is optional, so imports stay deferred until a Harbor task loads.
278
246
  from harbor.models.task.config import NetworkMode
279
- from harbor.models.task.config import TaskConfig as HarborTaskConfig
280
-
281
- config = tomllib.loads((task_dir / "task.toml").read_text())
282
- parsed = HarborTaskConfig.model_validate(config)
283
- network = (
284
- parsed.agent.explicit_phase_policy() or parsed.environment.resolve_baseline()
247
+ from harbor.models.task.task import Task as HarborModelTask
248
+
249
+ harbor_task = HarborModelTask(task_dir)
250
+ parsed = harbor_task.config
251
+ environment = parsed.environment
252
+ network = parsed.agent.explicit_phase_policy() or environment.resolve_baseline()
253
+ task, meta = parsed.task, parsed.metadata
254
+ authors = (
255
+ [Author(name=author.name, email=author.email) for author in task.authors]
256
+ if task
257
+ else []
285
258
  )
286
- task, meta = config.get("task", {}), config.get("metadata", {})
287
- authors = [Author(**a) for a in task.get("authors", [])]
288
259
  # Older registry entries stored one author in [metadata].
289
260
  if not authors and meta.get("author_name"):
290
261
  authors = [Author(name=meta["author_name"], email=meta.get("author_email"))]
291
262
  if harbor_config.ignore_timeouts:
292
263
  harness_timeout = scoring_timeout = None
293
264
  else:
294
- harness_timeout = config.get("agent", {}).get("timeout_sec")
295
- scoring_timeout = config.get("verifier", {}).get("timeout_sec")
265
+ harness_timeout = (
266
+ parsed.agent.timeout_sec
267
+ if "timeout_sec" in parsed.agent.model_fields_set
268
+ else None
269
+ )
270
+ scoring_timeout = (
271
+ parsed.verifier.timeout_sec
272
+ if "timeout_sec" in parsed.verifier.model_fields_set
273
+ else None
274
+ )
296
275
  return HarborData(
297
276
  idx=idx,
298
- name=task.get("name") or task_dir.name,
299
- description=task.get("description"),
300
- prompt=(task_dir / "instruction.md").read_text().strip(),
277
+ name=harbor_task.name,
278
+ description=task.description if task else None,
279
+ prompt=harbor_task.instruction.strip(),
301
280
  image=resolve_image(
302
281
  task_dir,
303
- config,
282
+ environment.docker_image,
304
283
  harbor_config.require_image,
305
284
  harbor_config.ignore_dockerfile,
306
285
  ),
286
+ workdir=environment.workdir,
307
287
  network_allow=(
308
288
  ["*"]
309
289
  if network.network_mode == NetworkMode.PUBLIC
@@ -317,16 +297,25 @@ def parse_task(task_dir: Path, idx: int, harbor_config: HarborConfig) -> HarborD
317
297
  if scoring_timeout is not None
318
298
  else None,
319
299
  ),
320
- resources=parse_resources(
321
- config.get("environment", {}), harbor_config.resource_multiplier
300
+ resources=TaskResources(
301
+ cpu=environment.cpus * harbor_config.resource_multiplier
302
+ if environment.cpus
303
+ else None,
304
+ memory=environment.memory_mb / 1024 * harbor_config.resource_multiplier
305
+ if environment.memory_mb
306
+ else None,
307
+ gpu=str(environment.gpus) if environment.gpus else None,
308
+ disk=environment.storage_mb / 1024 * harbor_config.resource_multiplier
309
+ if environment.storage_mb
310
+ else None,
322
311
  ),
323
- keywords=task.get("keywords", []),
312
+ keywords=task.keywords if task else [],
324
313
  authors=authors,
325
314
  difficulty=meta.get("difficulty"),
326
315
  category=meta.get("category"),
327
316
  tags=meta.get("tags", []),
328
317
  task_dir=str(task_dir),
329
- verifier_env=config.get("verifier", {}).get("env", {}),
318
+ verifier_env=parsed.verifier.env,
330
319
  )
331
320
 
332
321
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: verifiers
3
- Version: 0.2.2.dev40
3
+ Version: 0.2.2.dev42
4
4
  Summary: Verifiers: Environments for LLM Reinforcement Learning
5
5
  Project-URL: Homepage, https://github.com/primeintellect-ai/verifiers
6
6
  Project-URL: Documentation, https://github.com/primeintellect-ai/verifiers
@@ -51,7 +51,7 @@ Provides-Extra: browser
51
51
  Requires-Dist: python-dotenv>=1.0.0; extra == 'browser'
52
52
  Requires-Dist: stagehand>=3.4.0; extra == 'browser'
53
53
  Provides-Extra: harbor
54
- Requires-Dist: harbor==0.14.0; (python_version >= '3.12') and extra == 'harbor'
54
+ Requires-Dist: harbor==0.20.0; (python_version >= '3.12') and extra == 'harbor'
55
55
  Provides-Extra: modal
56
56
  Requires-Dist: modal>=1.4.0; extra == 'modal'
57
57
  Provides-Extra: notebook
@@ -174,7 +174,7 @@ verifiers/v1/env.py,sha256=QFwhD1NKbEUWGf0l6G2ttK4JLbhUt2MUCDciWaaJ_1s,17834
174
174
  verifiers/v1/episode.py,sha256=KWyM9ovTphEIo2260BYu2HvtnOOTxjLRDPrF_jTCiuA,2497
175
175
  verifiers/v1/errors.py,sha256=Pj5Om8x1fP3TDPQQn6nUCoSPoZRsy2JeBz8pXhpPrDY,6883
176
176
  verifiers/v1/graph.py,sha256=-j8MNdIv1r5ifajv5ggnGPsfBNB74IO3WKLcrpYh9hg,29102
177
- verifiers/v1/harness.py,sha256=oL_CyPXw2ScCXfM-E0sk-7_y4PqvjxC8gq2jR2jyWUs,10709
177
+ verifiers/v1/harness.py,sha256=cDiDuhp29aqL4CxiqSZz-IT0QlOcVlye_vTTHZblWo8,10948
178
178
  verifiers/v1/judge.py,sha256=VnTi9iSfCJMCccYWc1qCTcT7iD3AcomS2cXfHwh1HVw,9423
179
179
  verifiers/v1/legacy.py,sha256=kGfx4CEmk17VEqwX6JfUBbjQRMqJ0tL4kkA2kqGypN8,22305
180
180
  verifiers/v1/loaders.py,sha256=TnNKY2msVo3p7m-5wjw376PYH-zTu3TLixXRst0VOiM,9985
@@ -272,7 +272,7 @@ verifiers/v1/harnesses/pool/harness.py,sha256=6DlOA2W3s-NrxdQ9GaMmZg7mSNJGz2GC21
272
272
  verifiers/v1/harnesses/rlm/__init__.py,sha256=hwx51xTdEWzzYgMj-p4ETNcptoub3IPMDbEdJ4uB8Ns,122
273
273
  verifiers/v1/harnesses/rlm/harness.py,sha256=LRllWSQjpoq-IrOWVCp1sNvBgivqZYz9pVUsarZBQfA,7208
274
274
  verifiers/v1/harnesses/terminus_2/__init__.py,sha256=l1pwfg1HyVDEqT9efdnFWcXqaZwtKwe7TrplkyxZSA0,166
275
- verifiers/v1/harnesses/terminus_2/harness.py,sha256=-kDpMii6FBX6RfN7iHGZ8p6ZwMp94OwDhocKIWxEg0E,3027
275
+ verifiers/v1/harnesses/terminus_2/harness.py,sha256=h-W2Yc4juKcg9YuGp7sZtJghTdu-S6pq4Wf5cP0VBeE,3027
276
276
  verifiers/v1/harnesses/terminus_2/program.py,sha256=XWflwULPfVUyrwAldXLRVOoUWoWW9bYNsaygWef0Sfg,2668
277
277
  verifiers/v1/interception/__init__.py,sha256=g2mLlps-NSlZjL3JJv76QBwVwMyMUaNt_9KsNrlgAAk,2980
278
278
  verifiers/v1/interception/base.py,sha256=WUsPqIkC9I3xnQCCjDCoX7jiJUiG_qt97oJrTKEgWY4,2698
@@ -292,7 +292,7 @@ verifiers/v1/mcp/launch.py,sha256=lRtcl98BO7imC44bsxO2yljwRQR_KCvJ6P-bd_hS5L8,18
292
292
  verifiers/v1/mcp/server.py,sha256=uW8qddXQbtECxIPCU-lkOlFIv3VKWoFAeZFNhwPoyWo,10985
293
293
  verifiers/v1/mcp/toolset.py,sha256=tSPXgTNREZyaeCnoFVnDfXxFAj_pStZMPUIgyPrY_Dk,996
294
294
  verifiers/v1/runtimes/__init__.py,sha256=TqNtJVahzQuLS4fgCVeT9xdOzTkp0hRAPOkl7eFVDUg,2011
295
- verifiers/v1/runtimes/base.py,sha256=hv1McFrIZgymLwMLNYPAlsR4At0uz60haVo5eXrFbNU,14196
295
+ verifiers/v1/runtimes/base.py,sha256=sTCiLo51yAU_T-Voc3BTH-FuzyEM0cGY05VzFE4DmYc,14720
296
296
  verifiers/v1/runtimes/limiters.py,sha256=ZjjYUFEt20yH8ggL5uU9w9U500AOB44qSUTQ7bYyh0c,2730
297
297
  verifiers/v1/runtimes/modal.py,sha256=FnocoJd9lQVQS3V3CoBon7KpKXm1bKWWeU2FAkq2bKU,8825
298
298
  verifiers/v1/runtimes/prime.py,sha256=wldpcZnKZHNRldpoubeMgHdl-ZlKWOyeulFu4nHNKwc,15110
@@ -306,7 +306,7 @@ verifiers/v1/serve/server.py,sha256=gTrSZYSG2DH-KpAhLMN2L1oaMC6oJrqtguNrDfgHQFU,
306
306
  verifiers/v1/serve/types.py,sha256=AHFbt8C-Rzlee34RDPLQ3lPiYDLkUm5eFMnRQINiO6s,3016
307
307
  verifiers/v1/tasksets/__init__.py,sha256=b62O4WDNbGfJH_4NjYmznn5otWovdfvUgJZyoIZyLh8,596
308
308
  verifiers/v1/tasksets/harbor/__init__.py,sha256=wwVGA8N7E2Q2qA5WGHuLRrn4DgG5oaRHrCS2RW3NXVY,195
309
- verifiers/v1/tasksets/harbor/taskset.py,sha256=zRztBPzsZnuMa7lCDBDvaAyB5fQ2jRRUDHvrKwujai0,14731
309
+ verifiers/v1/tasksets/harbor/taskset.py,sha256=aPgdVExCtt09t2YJrsK4UmlpQwAp5-htXa7arC1bX68,13877
310
310
  verifiers/v1/tasksets/lean/__init__.py,sha256=oyv-GbJQBvCyGwo7Ysxm2NjZW-aX4j1uDoHU0f-E7xQ,767
311
311
  verifiers/v1/tasksets/lean/scoring.py,sha256=sfzsT6MUK0zdMgAQ57_P_0CBaPHy3M7go71QMr5hDrs,10599
312
312
  verifiers/v1/tasksets/lean/taskset.py,sha256=0KujQgx2fTL_DyWSQidebKoD94U8oJp82PXoco6-3B4,9065
@@ -327,8 +327,8 @@ verifiers/v1/utils/logging.py,sha256=OcMHA6NsYux3oIzjPuI95rDWmFBHNcHDjZeNIhXTX-Y
327
327
  verifiers/v1/utils/memory.py,sha256=ZkIvGk6uITAH5sKon65LifKPbvZr8mJ__PVc23FZpOQ,1835
328
328
  verifiers/v1/utils/sampling.py,sha256=JczGzBn6s3wsIrSY2Hy3hE8m6NreNgsNzhSjDikQqX0,1037
329
329
  verifiers/v1/utils/version.py,sha256=-obEo_-l9-D8FLef4hYxncOe-uJpxrM1g2Hig_37Sgs,1607
330
- verifiers-0.2.2.dev40.dist-info/METADATA,sha256=7FRJgVM3XdGU4JTZSsGsxxaKndzkW26q4EFyz9NsMhE,4540
331
- verifiers-0.2.2.dev40.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
332
- verifiers-0.2.2.dev40.dist-info/entry_points.txt,sha256=dF82JUYEFslR1AOW8LZfuBWeZeQoyX4wCRrduklg8-I,551
333
- verifiers-0.2.2.dev40.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
334
- verifiers-0.2.2.dev40.dist-info/RECORD,,
330
+ verifiers-0.2.2.dev42.dist-info/METADATA,sha256=Sfv8yHjesqeUSatEPoWH_rvAosXXPvZ2xczF2O7_mzI,4540
331
+ verifiers-0.2.2.dev42.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
332
+ verifiers-0.2.2.dev42.dist-info/entry_points.txt,sha256=dF82JUYEFslR1AOW8LZfuBWeZeQoyX4wCRrduklg8-I,551
333
+ verifiers-0.2.2.dev42.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
334
+ verifiers-0.2.2.dev42.dist-info/RECORD,,