verifiers 0.3.2.dev50__py3-none-any.whl → 0.3.2.dev52__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.
@@ -78,12 +78,11 @@ class ACPHarness(Harness[ConfigT]):
78
78
  self, trace: Trace, response_metadata: dict[str, Any]
79
79
  ) -> None:
80
80
  """Attach optional protocol extensions understood by every ACP harness."""
81
- if ACP_SEMANTIC_EDGES_METADATA_KEY not in response_metadata:
82
- return
83
- edge_set = SemanticEdgeSet.model_validate(
84
- response_metadata[ACP_SEMANTIC_EDGES_METADATA_KEY]
85
- )
86
- trace.add_semantic_edges(edge_set)
81
+ if ACP_SEMANTIC_EDGES_METADATA_KEY in response_metadata:
82
+ edge_set = SemanticEdgeSet.model_validate(
83
+ response_metadata[ACP_SEMANTIC_EDGES_METADATA_KEY]
84
+ )
85
+ trace.add_semantic_edges(edge_set)
87
86
 
88
87
  @abstractmethod
89
88
  async def prepare_acp(
@@ -51,10 +51,13 @@ class CompactionConfig(BaseConfig):
51
51
  max_compactions: PositiveInt | None = None
52
52
  """Compactions per session before the engine stops compacting; `None` =
53
53
  nano-rlm's default."""
54
+ max_attempts: PositiveInt | None = None
55
+ """Summary-generation attempts within one compaction cycle; `None` =
56
+ nano-rlm's default (5)."""
54
57
 
55
58
 
56
59
  class RLMHarnessConfig(HarnessConfig):
57
- version: str = Field(default="dd2c04f", min_length=1)
60
+ version: str = Field(default="e384006", min_length=1)
58
61
  """Git ref (branch, tag, or commit) of nano-rlm to install. Must know every
59
62
  field this harness puts on the wire, i.e. be at least the default ref."""
60
63
  max_depth: NonNegativeInt | None = None
@@ -170,6 +173,7 @@ class RLMHarness(ACPHarness[RLMHarnessConfig]):
170
173
  policy_knobs["compaction"] = True
171
174
  policy_knobs["summarize_at_tokens"] = compaction.summarize_at_tokens
172
175
  policy_knobs["max_compactions"] = compaction.max_compactions
176
+ policy_knobs["max_compaction_attempts"] = compaction.max_attempts
173
177
  appends = [
174
178
  text
175
179
  for text in (system_prompt, self.config.append_to_system_prompt)
@@ -27,6 +27,7 @@ from verifiers.v1.runtimes.base import (
27
27
  RuntimeProcess,
28
28
  )
29
29
  from verifiers.v1.runtimes.limiters import creation_limiter
30
+ from verifiers.v1.utils.aio import run_shielded
30
31
 
31
32
  logger = logging.getLogger(__name__)
32
33
 
@@ -128,25 +129,7 @@ class ModalRuntime(Runtime):
128
129
  creation_limiter(self.config.creates_per_sec, "modal-sandbox")
129
130
  or contextlib.nullcontext()
130
131
  ):
131
- self._sandbox = await modal.Sandbox.create.aio(
132
- "sleep",
133
- "infinity", # keep-alive entrypoint; the harness runs via `exec`
134
- app=app,
135
- name=self.name,
136
- # Clear the image's ENTRYPOINT so `sleep infinity` runs as the command
137
- # rather than as args to it — otherwise an image with its own entrypoint
138
- # (e.g. SWE task images) never starts the keep-alive and the sandbox dies.
139
- image=modal.Image.from_registry(self.config.image).entrypoint([]),
140
- workdir=self.config.workdir,
141
- env=self.env,
142
- cpu=self.config.cpu,
143
- memory=int(self.config.memory * 1024), # Modal memory is MB
144
- gpu=self.config.gpu,
145
- region=self.config.region,
146
- block_network=not self.config.network_access,
147
- timeout=24 * 60 * 60, # Maximum lifetime of any sandbox.
148
- encrypted_ports=[SERVICE_PORT],
149
- )
132
+ await run_shielded(self._create_sandbox(app))
150
133
  self.info.id = self._sandbox.object_id
151
134
  logger.info(
152
135
  "modal: sandbox %s up (image=%s)", self.info.id, self.config.image
@@ -157,6 +140,37 @@ class ModalRuntime(Runtime):
157
140
  ) as e: # provisioning failure is one rollout's problem, not the eval's
158
141
  raise SandboxError(f"modal sandbox provisioning failed: {e}") from e
159
142
 
143
+ async def _create_sandbox(self, app) -> None:
144
+ """Create the sandbox and take ownership of the handle, as one shielded step.
145
+
146
+ Modal schedules the sandbox before `Sandbox.create` returns, so a cancellation
147
+ landing between those two points leaves a sandbox that boots and bills with
148
+ `_sandbox` still unset — invisible to both `teardown` and the atexit backstop, and
149
+ alive until its 24h maximum lifetime. Assigning inside the coroutine that
150
+ `run_shielded` owns keeps the cancellation pending until the handle is ours.
151
+ """
152
+ import modal
153
+
154
+ self._sandbox = await modal.Sandbox.create.aio(
155
+ "sleep",
156
+ "infinity", # keep-alive entrypoint; the harness runs via `exec`
157
+ app=app,
158
+ name=self.name,
159
+ # Clear the image's ENTRYPOINT so `sleep infinity` runs as the command rather
160
+ # than as args to it — otherwise an image with its own entrypoint (e.g. SWE
161
+ # task images) never starts the keep-alive and the sandbox dies.
162
+ image=modal.Image.from_registry(self.config.image).entrypoint([]),
163
+ workdir=self.config.workdir,
164
+ env=self.env,
165
+ cpu=self.config.cpu,
166
+ memory=int(self.config.memory * 1024), # Modal memory is MB
167
+ gpu=self.config.gpu,
168
+ region=self.config.region,
169
+ block_network=not self.config.network_access,
170
+ timeout=24 * 60 * 60, # Maximum lifetime of any sandbox.
171
+ encrypted_ports=[SERVICE_PORT],
172
+ )
173
+
160
174
  async def expose(self, port: int) -> str | None:
161
175
  # Publish a server hosted IN the sandbox: Modal forwards `port` (named via
162
176
  # `encrypted_ports` at creation) to a public URL, read back from `sandbox.tunnels()`.
verifiers/v1/semantic.py CHANGED
@@ -63,8 +63,8 @@ class SemanticEdgeSet(BaseModel):
63
63
  """A harness-published set of semantic edges over logical request IDs.
64
64
 
65
65
  Edge labels are intentionally extensible. Initial harnesses use ``continuation``,
66
- ``compaction``, ``subagent_call``, and ``subagent_return``; consumers must preserve
67
- unknown labels.
66
+ ``compaction_attempt``, ``compaction``, ``subagent_call``, and ``subagent_return``;
67
+ consumers must preserve unknown labels.
68
68
  """
69
69
 
70
70
  model_config = ConfigDict(extra="forbid", strict=True)
verifiers/v1/trace.py CHANGED
@@ -20,11 +20,7 @@ from verifiers.v1.configs.agent import AgentConfig, WireAgentConfig
20
20
  from verifiers.v1.errors import ProviderError
21
21
  from verifiers.v1.graph import RECORD_FLOAT_DECIMALS, MessageNode
22
22
  from verifiers.v1.runtimes import RuntimeInfo
23
- from verifiers.v1.semantic import (
24
- ACPInfo,
25
- ParentLink,
26
- SemanticEdgeSet,
27
- )
23
+ from verifiers.v1.semantic import ACPInfo, ParentLink, SemanticEdgeSet
28
24
  from verifiers.v1.state import State, StateT
29
25
  from verifiers.v1.task import DataT, WireTaskData
30
26
  from verifiers.v1.types import (
@@ -201,6 +197,8 @@ class Branch(BaseModel):
201
197
  index: int
202
198
  nodes: list[MessageNode]
203
199
  calls: list[ModelCall] = Field(default_factory=list)
200
+ trainable: bool = True
201
+ """Whether this physical path contributes a training sample."""
204
202
  mm_token_type_id_map: dict[int, int] = Field(default_factory=dict)
205
203
  """The trace's `mm_token_type_id_map`, carried so `mm_token_type_ids` is self-contained."""
206
204
 
@@ -492,8 +490,18 @@ class Trace(BaseModel, Generic[DataT, StateT, AgentConfigT]):
492
490
 
493
491
  @property
494
492
  def branches(self) -> list[Branch]:
495
- """One root-to-leaf path per graph leaf, its calls attached in path order."""
493
+ """One root-to-leaf view per graph leaf, with no duplicated node storage.
494
+
495
+ A compaction attempt is a dangling physical leaf. It is trainable only when
496
+ the final semantic graph shows that the harness resumed from it.
497
+ """
496
498
  by_node = {c.node: c for c in self.calls if c.node is not None}
499
+ accepted_compaction_attempts = {
500
+ link.node
501
+ for node in self.nodes
502
+ for link in node.semantic_parents
503
+ if link.type == "compaction"
504
+ }
497
505
  branches: list[Branch] = []
498
506
  for i, leaf in enumerate(graph.leaves(self)):
499
507
  path: list[int] = []
@@ -502,11 +510,19 @@ class Trace(BaseModel, Generic[DataT, StateT, AgentConfigT]):
502
510
  path.append(nid)
503
511
  nid = self.nodes[nid].parent
504
512
  path.reverse()
513
+ is_compaction_attempt = any(
514
+ link.type == "compaction_attempt"
515
+ for link in self.nodes[leaf].semantic_parents
516
+ )
505
517
  branches.append(
506
518
  Branch(
507
519
  index=i,
508
520
  nodes=[self.nodes[n] for n in path],
509
521
  calls=[by_node[n] for n in path if n in by_node],
522
+ trainable=(
523
+ not is_compaction_attempt
524
+ or leaf in accepted_compaction_attempts
525
+ ),
510
526
  mm_token_type_id_map=self.mm_token_type_id_map,
511
527
  )
512
528
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: verifiers
3
- Version: 0.3.2.dev50
3
+ Version: 0.3.2.dev52
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
@@ -9,14 +9,14 @@ verifiers/v1/graph.py,sha256=K6wKkoT_8TpNqPQISu2Xf0eHtAYW_KUGw0CteN5zr3c,36529
9
9
  verifiers/v1/harness.py,sha256=Yx-XCIs1HAmqv1F-nhCTDBUwAx51xQWNWgFcWL1WRTM,13777
10
10
  verifiers/v1/judge.py,sha256=uqn-djkK2_7Q3kOjkDo6ipOvV_HOvuLa9y6AoDjRux8,9618
11
11
  verifiers/v1/rollout.py,sha256=FT6ZYfSqkKOFa5tm52XDTLijKxqpeLr3x2MBdLIk4xk,24021
12
- verifiers/v1/semantic.py,sha256=wssvBSEpY_tgzpFUADG9-N4HkDXgCZvNQ1pdf6qAsS0,4680
12
+ verifiers/v1/semantic.py,sha256=VQ_buw6Ya6QtRoh_fiYI5Avs5RmIQCfWH0H0bQc4aoc,4704
13
13
  verifiers/v1/session.py,sha256=xM7JJJVJACk0JfH9RAN1Ts8gJJKr2tGGRiIgQTrdieY,18692
14
14
  verifiers/v1/state.py,sha256=EckF2bWp-vV4b1jYJ9sLI5xrfGuI5spIgYYwW926toI,595
15
15
  verifiers/v1/task.py,sha256=9YhllEDgoHSz72-1fcYwBADl-rOzASnrSVimLheWmwI,12237
16
16
  verifiers/v1/taskset.py,sha256=fp2E0IEhL_Ybj9cegZwljfTmW27p_30zTWHFKw_kXE4,4374
17
- verifiers/v1/trace.py,sha256=8KCGMF2iaUNH_PypKNx--QwbSsl5dUCGeXp9Dmkm-24,29623
17
+ verifiers/v1/trace.py,sha256=dBrStZXoEhVIKtcUzG6lZN0SEAjATOqBZCrgbaPdIXw,30398
18
18
  verifiers/v1/types.py,sha256=PH1SxRWXOjPCgQD9aZgM18_bECvFSNQ25gkCbulmTKU,9857
19
- verifiers/v1/acp/__init__.py,sha256=wUPZVYBFjJuOnIIoYONBFuA04A1DJf_dOyKY3QwK37Q,12722
19
+ verifiers/v1/acp/__init__.py,sha256=sbJL7vTE_BEmw34wwgbNPuWuAmQ_gwELsK3wQbT08f4,12715
20
20
  verifiers/v1/acp/runner.py,sha256=gMXFmsVg2qD0Zhrx7kvC6Me2Z-wsfBamRIO0i45UW8g,11097
21
21
  verifiers/v1/cli/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
22
22
  verifiers/v1/cli/debug.py,sha256=x3bqOwwbwwfwQQpxHrZeKdxsW3ZVtUT9cAn_r4aOro4,11631
@@ -112,7 +112,7 @@ verifiers/v1/harnesses/pool/harness.py,sha256=TsELYhW4mMOt_laiDN6nAQJxFL3iCcKvck
112
112
  verifiers/v1/harnesses/prime_agent/__init__.py,sha256=xfPC4RrlnyYWaf38tPAOZq4YL6M55lMpj5BoRLmaK8I,171
113
113
  verifiers/v1/harnesses/prime_agent/harness.py,sha256=CgrKBXoelwRiSH9fzsNnz4oykz_iDJ3p5WVGBOB9AeU,10906
114
114
  verifiers/v1/harnesses/rlm/__init__.py,sha256=hwx51xTdEWzzYgMj-p4ETNcptoub3IPMDbEdJ4uB8Ns,122
115
- verifiers/v1/harnesses/rlm/harness.py,sha256=DX6xPBdxdXhJz-LClThAj7f1ZJ5tgN03H_WBbYhKce4,10445
115
+ verifiers/v1/harnesses/rlm/harness.py,sha256=A-3lUD4t6kND5Hq01wedTbAcCWAlQvjqn-QQKBIYbi4,10671
116
116
  verifiers/v1/harnesses/terminus_2/__init__.py,sha256=l1pwfg1HyVDEqT9efdnFWcXqaZwtKwe7TrplkyxZSA0,166
117
117
  verifiers/v1/harnesses/terminus_2/harness.py,sha256=DMTY1bzvydyjHqzmvBSBGKJsmUzYEgxqd215a7cG7tg,3052
118
118
  verifiers/v1/harnesses/terminus_2/program.py,sha256=X8MZdyItU3gbXGXnGOlJ9LWcUTnqIDaxlhkZvoRiqKY,2703
@@ -143,7 +143,7 @@ verifiers/v1/mcp/toolset.py,sha256=G2wzNdEMGLXoQUcrwF0TartJkqokNPI3o7YUOAaaa6U,1
143
143
  verifiers/v1/runtimes/__init__.py,sha256=ppc1R_sx-aMcuJSx4t99rTSjloUXI0M6EUj676-1PeY,2862
144
144
  verifiers/v1/runtimes/base.py,sha256=SRTUNAcdW0xJIWjfS5RcijFXqdKyXmGvp2tvV58eu58,16826
145
145
  verifiers/v1/runtimes/limiters.py,sha256=C6cWDD4pwyFwUY4QFke3oiMXwydSNIfSbJSIglUC2kE,3062
146
- verifiers/v1/runtimes/modal.py,sha256=Lgc0OkQEWHVBHCqBE2ja-mxtRYGserixlO4B9b5Vwn4,12661
146
+ verifiers/v1/runtimes/modal.py,sha256=yyrqI6agpzi0lp5jR_ExqKwAq8tRgLvHVa3Sd3oh6RU,13222
147
147
  verifiers/v1/runtimes/prime.py,sha256=1IWRLKdGgscs8JmvkBdaS3au4tV0KUqv4W1gHJvOE2Q,18781
148
148
  verifiers/v1/runtimes/subprocess.py,sha256=IO82fI1wFbeTtV7T1AHSF8iTUyT9yGJFIUmCKKw6CnQ,7763
149
149
  verifiers/v1/runtimes/docker/__init__.py,sha256=K6xbJAT1F3-PtgP5Gum2UJKQ8Re1Yz90BP8Uc7Npec4,20594
@@ -189,8 +189,8 @@ verifiers/v1/utils/prime.py,sha256=UTYRjp9cbjNb6CVmBHda-1wWZAIIfxNOmTyNuT7_wL4,9
189
189
  verifiers/v1/utils/retries.py,sha256=Y2ZgrAjn-qNkRKZP_RVNL_7EK0iaRcZeCa404lpGYi4,5417
190
190
  verifiers/v1/utils/score.py,sha256=493yJVMw8teCu9JxapxMFPFzI0hNUqdo0Y2nGW4kckk,6200
191
191
  verifiers/v1/utils/version.py,sha256=-obEo_-l9-D8FLef4hYxncOe-uJpxrM1g2Hig_37Sgs,1607
192
- verifiers-0.3.2.dev50.dist-info/METADATA,sha256=mTpWsGyXsT89Id7rFwue1VwNmTo5zmMJDt_E-X-trlk,4153
193
- verifiers-0.3.2.dev50.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
194
- verifiers-0.3.2.dev50.dist-info/entry_points.txt,sha256=uqQje0TMsr7k6nXlWxlPs13Si0evb3pVCEDF6c-YL80,241
195
- verifiers-0.3.2.dev50.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
196
- verifiers-0.3.2.dev50.dist-info/RECORD,,
192
+ verifiers-0.3.2.dev52.dist-info/METADATA,sha256=g2XajQ0FKtnxFleFE_R5mxzDMXVNOapplm1pEpfhJ0o,4153
193
+ verifiers-0.3.2.dev52.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
194
+ verifiers-0.3.2.dev52.dist-info/entry_points.txt,sha256=uqQje0TMsr7k6nXlWxlPs13Si0evb3pVCEDF6c-YL80,241
195
+ verifiers-0.3.2.dev52.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
196
+ verifiers-0.3.2.dev52.dist-info/RECORD,,