verifiers 0.3.2.dev184__py3-none-any.whl → 0.3.2.dev187__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/__init__.py CHANGED
@@ -66,6 +66,8 @@ from verifiers.v1.harness import Harness, HarnessSession
66
66
  from verifiers.v1.judge import Judge, JudgeResponse, JudgeView
67
67
  from verifiers.v1.judges import (
68
68
  Criterion,
69
+ DecisionJudge,
70
+ DecisionJudgeConfig,
69
71
  ReferenceJudge,
70
72
  ReferenceJudgeConfig,
71
73
  RubricJudge,
@@ -358,6 +360,8 @@ __all__ = [ # noqa: RUF022 - grouped by public API area
358
360
  "Judges",
359
361
  "JudgeResponse",
360
362
  "JudgeView",
363
+ "DecisionJudge",
364
+ "DecisionJudgeConfig",
361
365
  "ReferenceJudge",
362
366
  "ReferenceJudgeConfig",
363
367
  "RubricJudge",
@@ -60,7 +60,10 @@ class BaseClientConfig(BaseConfig):
60
60
  or prime_config.get("inference_url")
61
61
  or DEFAULT_PRIME_INFERENCE_URL
62
62
  )
63
- if "base_url" not in self.model_fields_set:
63
+ if (
64
+ "base_url" not in self.model_fields_set
65
+ and self.base_url == DEFAULT_PRIME_INFERENCE_URL
66
+ ):
64
67
  self.base_url = prime_base_url
65
68
  host = urlparse(self.base_url).hostname or ""
66
69
  if host != PRIME_INFERENCE_HOST and not host.endswith(
@@ -40,7 +40,7 @@ def resolve_judges(entries: Sequence[Any]) -> list[JudgeConfig]:
40
40
  if not raw.get("id"):
41
41
  raise ValueError(
42
42
  "each `judges` entry needs an `id` (a judge plugin: `reference`, "
43
- "`rubric`, or an installed package)"
43
+ "`rubric`, `decision`, or an installed package)"
44
44
  )
45
45
  resolved.append(judge_config_type(raw["id"]).model_validate(raw))
46
46
  return resolved
@@ -51,7 +51,7 @@ def check_judges(entries: Sequence[JudgeConfig]) -> None:
51
51
  if not entry.id:
52
52
  raise ValueError(
53
53
  "each `judges` entry needs an `id` (a judge plugin: `reference`, "
54
- "`rubric`, or an installed package)"
54
+ "`rubric`, `decision`, or an installed package)"
55
55
  )
56
56
  keys = [judge_key(entry) for entry in entries]
57
57
  if duplicates := {key for key in keys if keys.count(key) > 1}:
@@ -1,8 +1,11 @@
1
+ from verifiers.v1.judges.decision import DecisionJudge, DecisionJudgeConfig
1
2
  from verifiers.v1.judges.reference import ReferenceJudge, ReferenceJudgeConfig
2
3
  from verifiers.v1.judges.rubric import Criterion, RubricJudge, RubricJudgeConfig
3
4
 
4
5
  __all__ = [
5
6
  "Criterion",
7
+ "DecisionJudge",
8
+ "DecisionJudgeConfig",
6
9
  "ReferenceJudge",
7
10
  "ReferenceJudgeConfig",
8
11
  "RubricJudge",
@@ -0,0 +1,105 @@
1
+ """Decision-model judge using Prime's evaluations API by default."""
2
+
3
+ import json
4
+ from typing import Any, cast
5
+
6
+ from pydantic import Field
7
+
8
+ from verifiers.v1.clients.base import build_async_openai
9
+ from verifiers.v1.configs.judge import JudgeConfig
10
+ from verifiers.v1.judge import (
11
+ Judge,
12
+ JudgeResponse,
13
+ JudgeView,
14
+ judge_question,
15
+ judge_response,
16
+ )
17
+ from verifiers.v1.task import TaskData
18
+ from verifiers.v1.trace import Trace
19
+ from verifiers.v1.types import ID, Usage
20
+
21
+
22
+ class DecisionJudgeConfig(JudgeConfig):
23
+ id: ID = "decision"
24
+ model: str = "typesafe-ai/jev"
25
+ base_url: str = "https://api.pinference.ai/api/v1/evaluations"
26
+ """Full URL to POST evaluation requests to."""
27
+ levels: list[str] = Field(
28
+ default_factory=lambda: ["Incorrect", "Correct"], min_length=2, max_length=10
29
+ )
30
+ """Grading levels, worst to best. The model's probability-weighted level is
31
+ normalized to [0, 1], so a two-level grade is the probability of correctness."""
32
+ question_field: str = ""
33
+ """Task field containing the question; empty uses the task's prompt text."""
34
+ answer_field: str = ""
35
+ """Optional task field containing a reference answer to include in the state."""
36
+ view: JudgeView = "last_reply"
37
+
38
+
39
+ class DecisionJudge(Judge[float, DecisionJudgeConfig]):
40
+ prompt = (
41
+ "Grade how well the response satisfies the task in question. "
42
+ "Use the reference answer when provided; equivalent answers are acceptable."
43
+ )
44
+
45
+ async def evaluate(
46
+ self, *, trace: Trace | None = None, **fields: Any
47
+ ) -> JudgeResponse[float]:
48
+ request = {
49
+ "model": self.config.model,
50
+ "state": fields,
51
+ "questions": {
52
+ "grade": {
53
+ "type": "score",
54
+ "instructions": self.build_messages(**fields),
55
+ "criteria": self.config.levels,
56
+ }
57
+ },
58
+ }
59
+ async with build_async_openai(self.config) as client:
60
+ raw = await client.post(
61
+ self.config.base_url, cast_to=dict[str, Any], body=request
62
+ )
63
+ result = raw.get("result", raw) # Workers AI wraps its response in `result`.
64
+ response = JudgeResponse[float](text=json.dumps(raw))
65
+ try:
66
+ if usage := result.get("usage"):
67
+ response.usage = Usage(
68
+ prompt_tokens=usage.get("inputTokens", usage.get("input_tokens")),
69
+ completion_tokens=usage.get(
70
+ "outputTokens", usage.get("output_tokens")
71
+ ),
72
+ cost=usage.get("cost"),
73
+ )
74
+ score = result["answers"]["grade"]["score"] / (len(self.config.levels) - 1)
75
+ if not 0 <= score <= 1:
76
+ raise ValueError(f"decision judge score {score!r} is outside [0, 1]")
77
+ response.parsed = score
78
+ return response
79
+ finally:
80
+ # The call was billed even if the score could not be parsed.
81
+ if trace is not None:
82
+ trace.record_judge_call(
83
+ name=self.reward_name, request=request, response=response
84
+ )
85
+
86
+ async def score(self, task: TaskData, trace: Trace) -> float:
87
+ response = judge_response(trace, self.config.view)
88
+ if not response.strip():
89
+ return 0.0
90
+ fields = {
91
+ "question": judge_question(task, self.config.question_field),
92
+ "response": response,
93
+ }
94
+ if self.config.answer_field:
95
+ answer = getattr(task, self.config.answer_field, None)
96
+ if answer is None:
97
+ raise ValueError(
98
+ f"decision judge found no {self.config.answer_field!r} field on the task"
99
+ )
100
+ fields["answer"] = answer
101
+ result = await self.evaluate(trace=trace, **fields)
102
+ return cast(float, result.parsed)
103
+
104
+
105
+ __all__ = ["DecisionJudge", "DecisionJudgeConfig"]
@@ -94,7 +94,10 @@ class PrimeConfig(NetworkPolicyConfig):
94
94
  gpu: str | None = None
95
95
  """GPU spec, e.g. "A100" or "A100:2" (a bare count = provider-chosen type)."""
96
96
  disk: float = 5.0
97
- """Disk in GB."""
97
+ """Disk in GB. Unused with ``checkpoint``: a sandbox keeps its checkpoint's disk."""
98
+ checkpoint: str | None = None
99
+ """A DURABLE filesystem checkpoint to start from instead of ``image`` (see the SDK's
100
+ ``checkpoint`` and ``wait_for_checkpoint``)."""
98
101
  idle_timeout: float | None = 3600
99
102
  """Seconds of inactivity before the sandbox self-deletes (None disables)."""
100
103
  creates_per_min: int | None = None
@@ -182,13 +185,19 @@ class PrimeRuntime(Runtime):
182
185
  options = {
183
186
  "cpu_cores": self.config.cpu,
184
187
  "memory_gb": self.config.memory,
185
- "disk_size_gb": self.config.disk,
186
188
  "gpu_count": gpu_count,
187
189
  "timeout_minutes": -1,
188
190
  "idle_timeout_minutes": idle_minutes,
189
191
  "gpu_type": gpu_type,
190
192
  "region": self.config.region,
191
193
  }
194
+ if self.config.checkpoint:
195
+ source = {"checkpoint_id": self.config.checkpoint}
196
+ else:
197
+ source = {
198
+ "docker_image": self.config.image,
199
+ "disk_size_gb": self.config.disk,
200
+ }
192
201
  scope = run_scope()
193
202
  labels = [*BASE_LABELS, *self.config.labels, scope]
194
203
  try:
@@ -208,7 +217,7 @@ class PrimeRuntime(Runtime):
208
217
  CreateSandboxRequest(
209
218
  name=self.name,
210
219
  labels=list(dict.fromkeys(labels)),
211
- docker_image=self.config.image,
220
+ **source,
212
221
  environment_vars=self.env,
213
222
  **{k: v for k, v in options.items() if v is not None},
214
223
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: verifiers
3
- Version: 0.3.2.dev184
3
+ Version: 0.3.2.dev187
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
@@ -36,7 +36,7 @@ Requires-Dist: numpy>=2.1.0
36
36
  Requires-Dist: openai<3.0.0,>=2.54.0
37
37
  Requires-Dist: prime-pydantic-config[toml]>=0.4.3
38
38
  Requires-Dist: prime-runs>=0.1.3
39
- Requires-Dist: prime-sandboxes>=0.4.1
39
+ Requires-Dist: prime-sandboxes>=0.4.2
40
40
  Requires-Dist: prime-tunnel>=0.1.8
41
41
  Requires-Dist: pydantic>=2.12.3
42
42
  Requires-Dist: pyzmq>=27.1.0
@@ -1,5 +1,5 @@
1
1
  verifiers/__init__.py,sha256=F5IVMw6mhGaPBMCw7QKk0la_r5mMwydP2hdTTdQucik,352
2
- verifiers/v1/__init__.py,sha256=ybCeLKoVNDU9nwla4BG8HrcZ2oXOuXquRBhaorGevxI,8792
2
+ verifiers/v1/__init__.py,sha256=xvS_VfN7QwTethhEJsZCi7lHicKvQdQKh2nhB2h9Lu8,8884
3
3
  verifiers/v1/agent.py,sha256=zBqbHDeqdPghg_QOkcyFplIDY3f34qCOtwcxJnl5N-U,45088
4
4
  verifiers/v1/env.py,sha256=fxXBjVyi0milYViHt6O0vBK3JdM2TYSOoQpXd0P0rFE,18110
5
5
  verifiers/v1/episode.py,sha256=UPtA02aGWA-fY8cJKEuYCMtQVnPN1C0BSN13LggNT8U,5986
@@ -43,10 +43,10 @@ verifiers/v1/clients/eval.py,sha256=x_5E8XnhFu4v-k4yI8WWHd39rDkvB7mSEPCVAWL4AiE,
43
43
  verifiers/v1/clients/train.py,sha256=lSJTwHjwOET3D_CI_eYZSoXSQcv2H0K5sYJ7kD_kdw4,19489
44
44
  verifiers/v1/configs/__init__.py,sha256=X7u6X7B3ieD1HZl79Tv1kg-yPHbT0QLvAebaGqxVtvA,317
45
45
  verifiers/v1/configs/agent.py,sha256=Vut73R2EW8QuL5c0iTnNFC_g-Obvl8YUKsjlvkABuL0,5311
46
- verifiers/v1/configs/client.py,sha256=vl46nrayZa84zrPBuEVpJIjDjbmYUIrDIuR0vZvvugw,5212
46
+ verifiers/v1/configs/client.py,sha256=i45QOop2Wb-LQRpNgUZGTCT1_HpNmdcG41eQrGMgJKQ,5297
47
47
  verifiers/v1/configs/env.py,sha256=k47XBYYWLOf-8P1dbek3x_s0ucNb726xxoryG69DIr4,7256
48
48
  verifiers/v1/configs/harness.py,sha256=ZrR-Egzfft95oMoqQ78bAq9TqP882Q68M_47Ajw9lE8,2918
49
- verifiers/v1/configs/judge.py,sha256=WEwA8D4X5JSaIP3c-E2wPnvgByWeT6JRAn1d8gfiQ40,2142
49
+ verifiers/v1/configs/judge.py,sha256=3ZvxcTf-3clj8bDLyaqsMSKCRclTQCvbyb2qp3QSRD8,2166
50
50
  verifiers/v1/configs/retries.py,sha256=BgpGbdMBmjyjcIGnvb5VTJzKMDA6TdKil-PBQaRwGZM,1770
51
51
  verifiers/v1/configs/runtime.py,sha256=3LDAnKy-BotE6MqyT1l07Y_bAq9Wye1OU8JZ7lyUVvY,5474
52
52
  verifiers/v1/configs/select.py,sha256=_HdcepQaJ1sDCYcs7Vqx72npDwHGOgUjsLDZmcgnonU,4743
@@ -131,7 +131,8 @@ verifiers/v1/interception/tunnel/__init__.py,sha256=eVNZJszj6myrKhx9jmJz7VRd9qlf
131
131
  verifiers/v1/interception/tunnel/base.py,sha256=DZB6uPLwM4Qy7n7m0vKeyg-Px87MhsmpYTpe2vpPEng,1998
132
132
  verifiers/v1/interception/tunnel/custom.py,sha256=yL4UbGf4bAuMsxk42mEP-t1wITQCT8BE9FHQIz0qRMA,1708
133
133
  verifiers/v1/interception/tunnel/prime.py,sha256=jVk_6xyrxXiHtsVFErcRNd4MoENdFbqzfC0i20nlizU,2803
134
- verifiers/v1/judges/__init__.py,sha256=MUIBWcx6c70BykrTDHhB0ITIyJPxXe6xDBou4VM7jDQ,286
134
+ verifiers/v1/judges/__init__.py,sha256=z-16awBqEZJrlVYIb9HD-rk12RaABh6jodJgwX4blnA,410
135
+ verifiers/v1/judges/decision.py,sha256=U8BKuzJVMWfX76fa6jaG_rmcOhzMkZoXSnkUuHKpoV4,3991
135
136
  verifiers/v1/judges/reference.py,sha256=iEVHw-iJ6dbwLOOqrvWrEMJOcUEYJ0YspT04rZz7Sd4,3868
136
137
  verifiers/v1/judges/reference.txt,sha256=Ej35kGXiT2uJ0LcHIeez49rCS_9uHmCQKoVdn93V6A8,353
137
138
  verifiers/v1/judges/rubric.py,sha256=HGQYI3xdq8I84Ce0_sDeNgk5JM597es8rOVPipjCyxU,12025
@@ -147,7 +148,7 @@ verifiers/v1/runtimes/container.py,sha256=_hNhGOo1Zvorj7THSj2UrZTkgewySUVJe4Kd77
147
148
  verifiers/v1/runtimes/e2b.py,sha256=yBeocAutsv2l5x-C5IMqrlgBz6Cb-t6vWbX4qTjlztE,30306
148
149
  verifiers/v1/runtimes/limiters.py,sha256=rOfQJcMdYcLSKq8AL9O09BfGOLqpYmNgrCxXXNcHLmU,2849
149
150
  verifiers/v1/runtimes/modal.py,sha256=ZHA4vtNIZwTV-bnVUlambgc8l34j_ZulvtrwvvkE2Kg,17945
150
- verifiers/v1/runtimes/prime.py,sha256=pkrHMWzBdmkNRBBelnu_fV5LO2kdEQmVlm0G2p7uZEk,19403
151
+ verifiers/v1/runtimes/prime.py,sha256=hGjkR8KsBy1OiUeJwcgmN8-twKnCVKk5IkUvm3-eWbs,19827
151
152
  verifiers/v1/runtimes/subprocess.py,sha256=vnGVAI3J7pYmRei4MQ7MN4nb8SglLi70NtVTINMPVvQ,8855
152
153
  verifiers/v1/runtimes/docker/__init__.py,sha256=QoFOTMgRjoWD--O25Jsft9eD2vjcrMpJQyhfQXqWraI,21828
153
154
  verifiers/v1/runtimes/docker/egress.py,sha256=wtKWTL2_zFidxMR7lDRmfevQlOsl2Iyk88ebdO4Kqqw,24566
@@ -194,8 +195,8 @@ verifiers/v1/utils/scope.py,sha256=bzUEiWDOVdbj7dXOwGOlzsQ_-Xu0j9NR5TalQB-8TS8,8
194
195
  verifiers/v1/utils/score.py,sha256=493yJVMw8teCu9JxapxMFPFzI0hNUqdo0Y2nGW4kckk,6200
195
196
  verifiers/v1/utils/trace_store.py,sha256=RsCDonGR-bs-tvEstcppiJm3jFmAdIiG83fA5KtCbAw,2801
196
197
  verifiers/v1/utils/version.py,sha256=-obEo_-l9-D8FLef4hYxncOe-uJpxrM1g2Hig_37Sgs,1607
197
- verifiers-0.3.2.dev184.dist-info/METADATA,sha256=2jIg7eRwvlbVGsPE_AYQvvGKAPnBCZiY1E7GXeE66Ck,4227
198
- verifiers-0.3.2.dev184.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
199
- verifiers-0.3.2.dev184.dist-info/entry_points.txt,sha256=iugElcdWPKbQM7uFF0lZ8iUpHsNr17-BwEAAjJWxV3U,259
200
- verifiers-0.3.2.dev184.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
201
- verifiers-0.3.2.dev184.dist-info/RECORD,,
198
+ verifiers-0.3.2.dev187.dist-info/METADATA,sha256=V332qzc0c561uWvf-lUpwy5TaK0c6HWiBb-MstE1DRo,4227
199
+ verifiers-0.3.2.dev187.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
200
+ verifiers-0.3.2.dev187.dist-info/entry_points.txt,sha256=iugElcdWPKbQM7uFF0lZ8iUpHsNr17-BwEAAjJWxV3U,259
201
+ verifiers-0.3.2.dev187.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
202
+ verifiers-0.3.2.dev187.dist-info/RECORD,,