verifiers 0.4.2.dev44__py3-none-any.whl → 0.4.2.dev46__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.
@@ -101,6 +101,9 @@ class RLMHarnessConfig(HarnessConfig):
101
101
  exec_timeout: PositiveInt | None = None
102
102
  """IPython/native tool execution timeout in seconds; `None` uses nano-rlm's
103
103
  default (300). Separate from `tool_timeout`, which controls MCP calls."""
104
+ provider_max_retries: NonNegativeInt | None = None
105
+ """SDK retries per model call (429, 5xx, connection errors); `None` uses nano-rlm's
106
+ default (5). Raise it so long rollouts ride out extended rate-limit bursts."""
104
107
  allow_git: bool | None = None
105
108
  """Allow unrestricted Git history queries (e.g. `git log --all`); `None` uses
106
109
  nano-rlm's default (false). Ordinary Git commands remain allowed either way;
@@ -225,6 +228,11 @@ class RLMHarness(ACPHarness[RLMHarnessConfig]):
225
228
  "provider": {
226
229
  "base_url": endpoint,
227
230
  "api_key": secret,
231
+ **(
232
+ {"max_retries": self.config.provider_max_retries}
233
+ if self.config.provider_max_retries is not None
234
+ else {}
235
+ ),
228
236
  },
229
237
  # None = passthrough: the key stays off the wire and nano-rlm's own
230
238
  # default applies.
@@ -43,16 +43,8 @@ logger = get_logger(__name__)
43
43
  EFFECTIVELY_UNBOUNDED_SECONDS = 30 * 24 * 60 * 60
44
44
  """Safety deadline for APIs that require a finite bound. Normal execution remains
45
45
  bounded by idle detection or rollout cancellation; 30 days is above any real run."""
46
- # The SDK reads finished jobs' output through a bounded pool whose deadline includes time
47
- # spent queued; its defaults (20 reads, 45s) expire most reads when thousands of rollouts
48
- # finish a job at once (e.g. every harness's setup at a 3k-rollout start).
49
- _OUTPUT_READS = 100
50
- """Concurrent output reads on the shared client."""
51
- _OUTPUT_DEADLINE_SECONDS = 300
52
- """Deadline for one read of a finished job's output, queue time included."""
53
- _OUTPUT_RETRIES = 10
54
- """Re-reads of a finished job's output that the SDK still failed to fetch, before the
55
- exec is reported as failed."""
46
+ _OUTPUT_TAIL_BYTES = 10 * 1024 * 1024
47
+ """Maximum retained bytes per command output stream."""
56
48
  _PUBLIC_DOMAIN = "sandbox-v2-prod.pinfra.io"
57
49
  """Domain of the public URLs `https://<port>-<sandbox-id>.<domain>` that a LAN network's
58
50
  `internet` rule publishes ports at."""
@@ -69,8 +61,8 @@ class _SharedClient:
69
61
 
70
62
 
71
63
  # One `AsyncSandboxClient` per event loop, leased by every live runtime on it. The SDK
72
- # coalesces concurrent status polls per client into batched requests (up to 100 ids
73
- # each), so sharing a client turns N runtimes' creation/job polls into a few batch
64
+ # coalesces concurrent creation polls per client into batched requests (up to 100 ids
65
+ # each), so sharing a client turns N runtimes' creation polls into a few batch
74
66
  # calls. Keyed by loop (not plain process-global) so a client's tasks stay on the loop
75
67
  # that created it.
76
68
  _shared_clients: dict[asyncio.AbstractEventLoop, _SharedClient] = {}
@@ -82,9 +74,7 @@ def _lease_client() -> Any:
82
74
  loop = asyncio.get_running_loop()
83
75
  shared = _shared_clients.get(loop)
84
76
  if shared is None:
85
- shared = _shared_clients[loop] = _SharedClient(
86
- AsyncSandboxClient(background_job_output_concurrency=_OUTPUT_READS)
87
- )
77
+ shared = _shared_clients[loop] = _SharedClient(AsyncSandboxClient())
88
78
  shared.leases += 1
89
79
  return shared.client
90
80
 
@@ -339,46 +329,39 @@ class PrimeBackend(RuntimeBackend):
339
329
  async def run(
340
330
  self, runtime: Runtime, argv: list[str], env: dict[str, str]
341
331
  ) -> ProgramResult:
332
+ async def collect(stream: AsyncIterator[bytes]) -> bytes:
333
+ tail = bytearray()
334
+ async for chunk in stream:
335
+ tail.extend(chunk[-_OUTPUT_TAIL_BYTES:])
336
+ del tail[:-_OUTPUT_TAIL_BYTES]
337
+ return bytes(tail)
338
+
342
339
  try:
343
- # Poll directly so rollout cancellation owns the execution timeout.
344
- job = await self._client.start_background_job(
340
+ # Command sessions survive task cleanup of shared scratch directories.
341
+ # Close stdin explicitly: the live-process API keeps it open by default.
342
+ process = await self._client.open_process(
345
343
  self.info.id,
346
- shlex.join(argv),
344
+ "exec "
345
+ + shlex.join(["sh", "-c", 'exec "$@" < /dev/null', "sh", *argv]),
347
346
  working_dir=self.config.workdir,
348
347
  env=runtime.process_env(env),
349
348
  user=runtime.user,
350
349
  )
351
- delay = 0.1
352
- output_retries = 0
353
- missing = None
354
- while True:
355
- result = await self._client.get_background_job(
356
- self.info.id, job, timeout=_OUTPUT_DEADLINE_SECONDS
350
+ try:
351
+ stdout, stderr, exit_code = await asyncio.gather(
352
+ collect(process.stdout), collect(process.stderr), process.wait()
357
353
  )
358
- # Under load the SDK can see a job finish yet miss its output (its bounded
359
- # output reads expire while queued) and reports that as `*_error`. The job
360
- # is done, so asking again re-reads the output.
361
- missing = result.stdout_error or result.stderr_error
362
- if result.completed and (
363
- missing is None or output_retries == _OUTPUT_RETRIES
364
- ):
365
- break
366
- if result.completed:
367
- output_retries += 1
368
- await asyncio.sleep(delay)
369
- delay = min(delay * 2, 3)
354
+ finally:
355
+ # Closing signals and reaps a running process, then releases its stream.
356
+ await run_shielded(process.aclose())
370
357
  except (
371
358
  Exception
372
359
  ) as e: # a sandbox/API failure is one rollout's problem, not the eval's
373
360
  raise SandboxError(f"prime exec failed: {e}") from e
374
- if missing is not None:
375
- raise SandboxError(f"prime exec output unavailable: {missing}")
376
- if result.exit_code is None:
377
- raise SandboxError("prime exec completed without an exit code")
378
361
  return ProgramResult(
379
- exit_code=result.exit_code,
380
- stdout=result.stdout or "",
381
- stderr=result.stderr or "",
362
+ exit_code=exit_code,
363
+ stdout=stdout.decode(errors="replace"),
364
+ stderr=stderr.decode(errors="replace"),
382
365
  )
383
366
 
384
367
  async def exec(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: verifiers
3
- Version: 0.4.2.dev44
3
+ Version: 0.4.2.dev46
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
@@ -105,7 +105,7 @@ verifiers/v1/harnesses/pi/harness.py,sha256=K2FtvDhoAUU_CdKVqE_NmDwsw3vqlSaZuLJW
105
105
  verifiers/v1/harnesses/prime_agent/__init__.py,sha256=xfPC4RrlnyYWaf38tPAOZq4YL6M55lMpj5BoRLmaK8I,171
106
106
  verifiers/v1/harnesses/prime_agent/harness.py,sha256=sV82MCi7uZTKlOH8Vg9_WSytgZNSbknShOhmYcdPPaE,12354
107
107
  verifiers/v1/harnesses/rlm/__init__.py,sha256=hwx51xTdEWzzYgMj-p4ETNcptoub3IPMDbEdJ4uB8Ns,122
108
- verifiers/v1/harnesses/rlm/harness.py,sha256=4Q6g93YJp9JQQWoCaNRYX6ojaMzoBGEuSHbChnJYprg,14873
108
+ verifiers/v1/harnesses/rlm/harness.py,sha256=ehWNA6MgSlKJ8Ee9pC_7WAxIVKUzAImAJn1SJYj5K7M,15304
109
109
  verifiers/v1/harnesses/stirrup/__init__.py,sha256=a-NQxX1bOwaGx8QHj2jWcRJEGiLIxdY6XUMbojr9dOk,142
110
110
  verifiers/v1/harnesses/stirrup/harness.py,sha256=ypWsg89r4CTeMy5hQVS8z8CUt9AUWgSVDidKjxZDqag,3139
111
111
  verifiers/v1/harnesses/stirrup/program.py,sha256=ks7hxFVc1Y_wQGhlUdFI62LeJBrAYgczZ0aioXSynm8,14939
@@ -149,7 +149,7 @@ verifiers/v1/runtimes/runtime.py,sha256=-CvhH42y0F0dPeNgDRVBeajkRK_vZYp2qxKY1XVf
149
149
  verifiers/v1/runtimes/strategies.py,sha256=WtIrIpKmvjvqpUfwLUwDNJcgRLE8d-2sx7reks2S2PA,8765
150
150
  verifiers/v1/runtimes/backends/custom.py,sha256=Iz1Brd4dBTpO1zYVc2KA0u5sxz5ZUROY_Cdme5W33hM,2875
151
151
  verifiers/v1/runtimes/backends/docker.py,sha256=uOjmENxhdQ9GPrvtQCXi1-6TL3fSRcflg6sENBOTM-w,31591
152
- verifiers/v1/runtimes/backends/prime.py,sha256=qTTIrmMbEluKIwHQ4kwRnKXn6RIT-P3mZtkxgh_wJ-4,24758
152
+ verifiers/v1/runtimes/backends/prime.py,sha256=vMD3d1JxyKWO5Zbd1c0DJ2I4DjdIFhi4XlgYabd1v4A,23884
153
153
  verifiers/v1/runtimes/backends/subprocess.py,sha256=naOWJGmcaOlu2ZdRbUwhJicJdxASDRAUhDT0jzDff3w,8591
154
154
  verifiers/v1/tasksets/__init__.py,sha256=2ijE3qIlLoUA02g6iysOwWQylyBBQL1GhSpjv8_bp0w,521
155
155
  verifiers/v1/tasksets/harbor/__init__.py,sha256=FjW4tM3rgGALMK-8p7ux26G4-d4ZFVmaAmO6Fni6e_g,214
@@ -187,8 +187,8 @@ verifiers/v1/utils/scope.py,sha256=zbs4pj6AVk4jywlAJ3AX0Q0_kzB9dBB02nY-9H4ELdQ,8
187
187
  verifiers/v1/utils/score.py,sha256=493yJVMw8teCu9JxapxMFPFzI0hNUqdo0Y2nGW4kckk,6200
188
188
  verifiers/v1/utils/trace_store.py,sha256=Qo9qvsJAl8PoRUavjQAfUB2VNxmUtYQtU2ejLKPzY9c,3382
189
189
  verifiers/v1/utils/version.py,sha256=-obEo_-l9-D8FLef4hYxncOe-uJpxrM1g2Hig_37Sgs,1607
190
- verifiers-0.4.2.dev44.dist-info/METADATA,sha256=1QsclZmVbRWmAKlpEy0XS6It5xZpqx0mfwtAzwiH7VA,5115
191
- verifiers-0.4.2.dev44.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
192
- verifiers-0.4.2.dev44.dist-info/entry_points.txt,sha256=qdMg7ajiFpDsHf7tuPMRclJXizu1J6LTWawS5YS0B0I,137
193
- verifiers-0.4.2.dev44.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
194
- verifiers-0.4.2.dev44.dist-info/RECORD,,
190
+ verifiers-0.4.2.dev46.dist-info/METADATA,sha256=OTP5cYrKTTt2rIGIAZceZC14T36z-qgm_1MPcs2bVok,5115
191
+ verifiers-0.4.2.dev46.dist-info/WHEEL,sha256=2iZrJkDIkeDh0k9SikKMqFuRP-ua6mb4Ir1AsER4BEw,87
192
+ verifiers-0.4.2.dev46.dist-info/entry_points.txt,sha256=qdMg7ajiFpDsHf7tuPMRclJXizu1J6LTWawS5YS0B0I,137
193
+ verifiers-0.4.2.dev46.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
194
+ verifiers-0.4.2.dev46.dist-info/RECORD,,