verifiers 0.3.2.dev101__py3-none-any.whl → 0.3.2.dev103__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/graph.py +41 -5
- verifiers/v1/serve/delta.py +49 -4
- {verifiers-0.3.2.dev101.dist-info → verifiers-0.3.2.dev103.dist-info}/METADATA +1 -1
- {verifiers-0.3.2.dev101.dist-info → verifiers-0.3.2.dev103.dist-info}/RECORD +7 -7
- {verifiers-0.3.2.dev101.dist-info → verifiers-0.3.2.dev103.dist-info}/WHEEL +0 -0
- {verifiers-0.3.2.dev101.dist-info → verifiers-0.3.2.dev103.dist-info}/entry_points.txt +0 -0
- {verifiers-0.3.2.dev101.dist-info → verifiers-0.3.2.dev103.dist-info}/licenses/LICENSE +0 -0
verifiers/v1/graph.py
CHANGED
|
@@ -673,8 +673,41 @@ def _attribute_mm(
|
|
|
673
673
|
)
|
|
674
674
|
|
|
675
675
|
|
|
676
|
+
def _replace_placeholder_routing_row(
|
|
677
|
+
trace: Trace, prefix_node_ids: list[int], arr: np.ndarray, off: int
|
|
678
|
+
) -> None:
|
|
679
|
+
"""Replace the prefix's placeholder routing row with the one this turn's prefill forwarded."""
|
|
680
|
+
if not 1 <= off <= arr.shape[0]:
|
|
681
|
+
return
|
|
682
|
+
# Only assistant (`sampled`) nodes are affected: the model forward isn't run on the final
|
|
683
|
+
# generated token for such turns, meaning its routing decisions are fundamentally unavailable.
|
|
684
|
+
# But, because routing needs one row per token, that row instead receives an inaccurate
|
|
685
|
+
# placeholder, attempt to fix up below.
|
|
686
|
+
node_with_placeholder = None
|
|
687
|
+
for nid in reversed(prefix_node_ids):
|
|
688
|
+
if trace.nodes[nid].token_ids:
|
|
689
|
+
node_with_placeholder = trace.nodes[nid]
|
|
690
|
+
break
|
|
691
|
+
if node_with_placeholder is None or not node_with_placeholder.sampled:
|
|
692
|
+
return
|
|
693
|
+
node_rows = node_with_placeholder.routed_experts
|
|
694
|
+
if (
|
|
695
|
+
node_rows is None
|
|
696
|
+
or node_rows.shape[0] == 0
|
|
697
|
+
or node_rows.shape[1:] != arr.shape[1:]
|
|
698
|
+
):
|
|
699
|
+
return
|
|
700
|
+
# Row `i` of this turn's array is sequence position `start + i`, so the prefix's final position
|
|
701
|
+
# is `arr[off - 1]`. Concatenating widens the node when this turn serialized `uint16`, where an
|
|
702
|
+
# in-place write would truncate.
|
|
703
|
+
node_with_placeholder.routed_experts = np.concatenate(
|
|
704
|
+
[node_rows[:-1], arr[off - 1 : off]], axis=0
|
|
705
|
+
)
|
|
706
|
+
|
|
707
|
+
|
|
676
708
|
def _attribute_routed_experts(
|
|
677
709
|
trace: Trace,
|
|
710
|
+
prefix_node_ids: list[int],
|
|
678
711
|
new_node_ids: list[int],
|
|
679
712
|
path_len: int,
|
|
680
713
|
payload: Any,
|
|
@@ -683,7 +716,8 @@ def _attribute_routed_experts(
|
|
|
683
716
|
payload's array covers the turn's prompt+completion from `payload["start"]` (0 = from token
|
|
684
717
|
0); the nodes created this turn tile sequence positions `[path_len:]` in creation order, so
|
|
685
718
|
we hand each node `arr[off : off+len(node.token_ids)]` and advance. Reused-prefix nodes keep
|
|
686
|
-
the routing attributed when they were first created
|
|
719
|
+
the routing attributed when they were first created, except for the one position this turn
|
|
720
|
+
corrects (see `_replace_placeholder_routing_row`). A node whose slice falls outside the
|
|
687
721
|
array (a `start` past `path_len`, e.g. an unexpected prefix-cache delta) is left unset — the
|
|
688
722
|
branch then reports no routing rather than misaligning."""
|
|
689
723
|
if payload is None:
|
|
@@ -693,6 +727,7 @@ def _attribute_routed_experts(
|
|
|
693
727
|
payload["shape"]
|
|
694
728
|
)
|
|
695
729
|
off = path_len - int(payload.get("start", 0) or 0)
|
|
730
|
+
_replace_placeholder_routing_row(trace, prefix_node_ids, arr, off)
|
|
696
731
|
needed = off + sum(len(trace.nodes[nid].token_ids) for nid in new_node_ids)
|
|
697
732
|
for nid in new_node_ids:
|
|
698
733
|
n = len(trace.nodes[nid].token_ids)
|
|
@@ -701,8 +736,8 @@ def _attribute_routed_experts(
|
|
|
701
736
|
# Own only this node's rows; a view would retain the turn's full-context array.
|
|
702
737
|
trace.nodes[nid].routed_experts = arr[off:end].copy()
|
|
703
738
|
elif n and arr.shape[0] and 0 <= off and end == needed == arr.shape[0] + 1:
|
|
704
|
-
#
|
|
705
|
-
#
|
|
739
|
+
# No forward pass follows the turn's final position, so it gets a placeholder: a
|
|
740
|
+
# copy of the previous row, appended to this node's slice of the array.
|
|
706
741
|
trace.nodes[nid].routed_experts = np.concatenate(
|
|
707
742
|
[arr[off:], arr[-1:]], axis=0
|
|
708
743
|
)
|
|
@@ -813,7 +848,7 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
|
|
|
813
848
|
parent = prefix[-1] if prefix else None
|
|
814
849
|
# cursor: in prompt_ids, the end of the previous *new* message's tokens
|
|
815
850
|
cursor: int | None = None
|
|
816
|
-
# Track new nodes separately so routed-expert attribution
|
|
851
|
+
# Track new nodes separately so routed-expert attribution needs only node ids, not this path.
|
|
817
852
|
new_node_ids: list[int] = []
|
|
818
853
|
# Materialize the reused message path only for multimodal cursor attribution.
|
|
819
854
|
mm_path: list[tuple[int, Message]] | None = None
|
|
@@ -874,8 +909,9 @@ def _commit_turn(turn: PendingTurn, response: Response) -> int:
|
|
|
874
909
|
|
|
875
910
|
# Attribute this turn's expert-routing array onto the nodes created this turn (new input
|
|
876
911
|
# nodes in creation order, then the assistant node), each getting the routing for its tokens.
|
|
912
|
+
# The prefix goes in too, so the position the previous turn could only pad can be corrected.
|
|
877
913
|
_attribute_routed_experts(
|
|
878
|
-
trace, new_node_ids, path_len, tokens.routed_experts if tokens else None
|
|
914
|
+
trace, prefix, new_node_ids, path_len, tokens.routed_experts if tokens else None
|
|
879
915
|
)
|
|
880
916
|
|
|
881
917
|
# Sampling masks are completion-aligned, so only the sampled node carries them.
|
verifiers/v1/serve/delta.py
CHANGED
|
@@ -4,12 +4,12 @@ The worker streams a served episode as it grows. Each trace announces its own ch
|
|
|
4
4
|
(`Trace.notify`, fired by the rollout at every phase change and by the interception proxy
|
|
5
5
|
after every recorded turn); the `DeltaStreamer` then diffs the run's live traces against
|
|
6
6
|
what it has already sent and ships only the new part — the trace header once, then
|
|
7
|
-
appended nodes / calls / errors, semantic links
|
|
7
|
+
appended nodes / calls / errors, semantic links and routing-row repairs on earlier nodes, the scalar
|
|
8
8
|
fields whose value changed (timing spans, stop condition, rewards, ...), and the
|
|
9
9
|
`pending` preview — the messages of the request in flight that no node holds yet, so a
|
|
10
10
|
watcher sees a tool result before the model has answered it. The `Trace` is
|
|
11
|
-
append-only at turn granularity
|
|
12
|
-
|
|
11
|
+
append-only at turn granularity except for links and the last routing row of a node,
|
|
12
|
+
which the next prefill can repair. Apart from these and the preview, every byte of the
|
|
13
13
|
episode crosses the wire once and the stream costs about what a single reply would; the
|
|
14
14
|
reply that ends the run carries only the episode head and per-trace counts the client
|
|
15
15
|
checks its assembly against. A cursor advances only once its delta is on the wire, so a
|
|
@@ -29,8 +29,10 @@ from collections.abc import Awaitable, Callable
|
|
|
29
29
|
from typing import TYPE_CHECKING, Any, Self
|
|
30
30
|
|
|
31
31
|
import msgpack
|
|
32
|
+
import numpy as np
|
|
32
33
|
from pydantic import BaseModel
|
|
33
34
|
|
|
35
|
+
from verifiers.v1.graph import _decode_ndarray, _encode_ndarray
|
|
34
36
|
from verifiers.v1.serve.encoding import msgpack_encoder
|
|
35
37
|
|
|
36
38
|
if TYPE_CHECKING:
|
|
@@ -73,7 +75,7 @@ def pack(payload: Any) -> bytes:
|
|
|
73
75
|
|
|
74
76
|
|
|
75
77
|
def unpack(data: bytes) -> Any:
|
|
76
|
-
#
|
|
78
|
+
# Node updates are keyed by node index (int).
|
|
77
79
|
return msgpack.unpackb(data, raw=False, strict_map_key=False)
|
|
78
80
|
|
|
79
81
|
|
|
@@ -90,6 +92,8 @@ class TraceCursor:
|
|
|
90
92
|
self.sent = dict.fromkeys(LIST_FIELDS, 0)
|
|
91
93
|
self.links: list[int] = []
|
|
92
94
|
"""Per sent node, how many of its semantic links went out with or after it."""
|
|
95
|
+
self.final_rows: dict[int, bytes] = {}
|
|
96
|
+
"""Per node that carries routing, its final row as packed when last sent."""
|
|
93
97
|
self.scalars: dict[str, bytes] = {}
|
|
94
98
|
self.pending: bytes = pack([])
|
|
95
99
|
|
|
@@ -157,6 +161,31 @@ class DeltaStreamer:
|
|
|
157
161
|
else:
|
|
158
162
|
self.cursors[trace_id] = cursor
|
|
159
163
|
|
|
164
|
+
def _maybe_add_routing_repairs(
|
|
165
|
+
self,
|
|
166
|
+
delta: dict[str, Any],
|
|
167
|
+
trace: Trace,
|
|
168
|
+
cursor: TraceCursor,
|
|
169
|
+
sent_nodes: int,
|
|
170
|
+
) -> None:
|
|
171
|
+
"""Add final rows repaired since they were sent, keyed by node index.
|
|
172
|
+
|
|
173
|
+
Record every node's current row on the cursor. `sent_nodes` is the pre-flush
|
|
174
|
+
count, so a node first sent in this delta is never reported as a repair.
|
|
175
|
+
"""
|
|
176
|
+
repairs: dict[int, dict] = {}
|
|
177
|
+
for index, node in enumerate(trace.nodes):
|
|
178
|
+
if node.routed_experts is None:
|
|
179
|
+
continue
|
|
180
|
+
row = _encode_ndarray(node.routed_experts[-1:])
|
|
181
|
+
packed = pack(row)
|
|
182
|
+
if cursor.final_rows.get(index) != packed:
|
|
183
|
+
cursor.final_rows[index] = packed
|
|
184
|
+
if index < sent_nodes:
|
|
185
|
+
repairs[index] = row
|
|
186
|
+
if repairs:
|
|
187
|
+
delta["routing_repairs"] = repairs
|
|
188
|
+
|
|
160
189
|
def diff(self) -> list[tuple[str, dict, TraceCursor | None]]:
|
|
161
190
|
"""Each trace's delta against its sent cursor, with the cursor as it stands once
|
|
162
191
|
that delta is sent (None for a discard). Nothing here is committed: `flush`
|
|
@@ -183,6 +212,7 @@ class DeltaStreamer:
|
|
|
183
212
|
cursor.links[index] = len(node_links)
|
|
184
213
|
if links:
|
|
185
214
|
delta["links"] = links
|
|
215
|
+
self._maybe_add_routing_repairs(delta, trace, cursor, cursor.sent["nodes"])
|
|
186
216
|
for field in LIST_FIELDS:
|
|
187
217
|
items = getattr(trace, field)
|
|
188
218
|
sent = cursor.sent[field]
|
|
@@ -220,6 +250,20 @@ class EpisodeAssembly:
|
|
|
220
250
|
def __init__(self) -> None:
|
|
221
251
|
self.traces: dict[str, dict] = {}
|
|
222
252
|
|
|
253
|
+
def _maybe_apply_routing_repairs(self, delta: dict[str, Any], trace: dict) -> None:
|
|
254
|
+
"""Replace repaired final rows in nodes the client already holds.
|
|
255
|
+
|
|
256
|
+
Rebuild each array: a repair can widen its dtype, and decoded rows alias
|
|
257
|
+
the original delta's bytes, which must remain unchanged for consumers.
|
|
258
|
+
"""
|
|
259
|
+
for index, row in (delta.get("routing_repairs") or {}).items():
|
|
260
|
+
node = trace["nodes"][int(index)]
|
|
261
|
+
node["routed_experts"] = _encode_ndarray(
|
|
262
|
+
np.concatenate(
|
|
263
|
+
[_decode_ndarray(node["routed_experts"])[:-1], _decode_ndarray(row)]
|
|
264
|
+
)
|
|
265
|
+
)
|
|
266
|
+
|
|
223
267
|
def apply(self, delta: dict) -> None:
|
|
224
268
|
trace_id = delta["trace"]
|
|
225
269
|
if delta.get("discard"):
|
|
@@ -234,6 +278,7 @@ class EpisodeAssembly:
|
|
|
234
278
|
}
|
|
235
279
|
for index, links in (delta.get("links") or {}).items():
|
|
236
280
|
trace["nodes"][int(index)]["semantic_parents"].extend(links)
|
|
281
|
+
self._maybe_apply_routing_repairs(delta, trace)
|
|
237
282
|
# a later `links` delta grows a node's semantic_parents in place, so the node
|
|
238
283
|
# is copied: the delta stays as it was when the caller received it
|
|
239
284
|
if "nodes" in delta:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: verifiers
|
|
3
|
-
Version: 0.3.2.
|
|
3
|
+
Version: 0.3.2.dev103
|
|
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
|
|
@@ -5,7 +5,7 @@ verifiers/v1/agent.py,sha256=rFjoAn9vpRXoyIZTzMgIuGb6HczTSuOenaB-U-x09to,32489
|
|
|
5
5
|
verifiers/v1/env.py,sha256=Hon7gcepciMYgki_jN4-l4XCcKRZRYuYm7c17nfeiFE,18520
|
|
6
6
|
verifiers/v1/episode.py,sha256=Fft0R2W6INAVeJhoE9b8h7L_KQSz7XuxP4FT_XhcsUY,5741
|
|
7
7
|
verifiers/v1/errors.py,sha256=uQySmCUrjDYFkBIii1vBFPiEcPFPQZ9EGpas_6HvcQI,5279
|
|
8
|
-
verifiers/v1/graph.py,sha256=
|
|
8
|
+
verifiers/v1/graph.py,sha256=b3Z3lCnsALnAvY82pDnjhODFYakkeLV_hXgGOvbryrQ,40737
|
|
9
9
|
verifiers/v1/harness.py,sha256=sXEjVdrS4A2SO35C_uEebBVeUt8VL7dui7IneAp2MRs,14124
|
|
10
10
|
verifiers/v1/judge.py,sha256=uqn-djkK2_7Q3kOjkDo6ipOvV_HOvuLa9y6AoDjRux8,9618
|
|
11
11
|
verifiers/v1/rollout.py,sha256=KjfxxIQIqk2X3ZbWUHUn-1nWl04JdYwdVj7ELJtKgbw,24168
|
|
@@ -149,7 +149,7 @@ verifiers/v1/runtimes/docker/__init__.py,sha256=2YJtjOVSA4OgxXgeIlFW3Ps01KEfLNT_
|
|
|
149
149
|
verifiers/v1/runtimes/docker/egress.py,sha256=iFH_1XotlEM-OCaW7GNu3TWVEq1sqesKYweyVBX8g90,14360
|
|
150
150
|
verifiers/v1/serve/__init__.py,sha256=wOKuwfugzmDT4yIniwzCXlf4G6tv6Cg8Kc--WMa38Bs,553
|
|
151
151
|
verifiers/v1/serve/client.py,sha256=E2y2x4qqYveWRWC9VZYQEu19aMEryPWTdXnYzbq5uTA,9829
|
|
152
|
-
verifiers/v1/serve/delta.py,sha256=
|
|
152
|
+
verifiers/v1/serve/delta.py,sha256=qhOUOYEt1wVzeaJ9IhjgU6ks5BkYOEtcFfGnuYxFEEs,13501
|
|
153
153
|
verifiers/v1/serve/encoding.py,sha256=hBZFucAZK9riXOV3DaHcskq9zHTT8gVGkoFVOPfnr30,2499
|
|
154
154
|
verifiers/v1/serve/pool.py,sha256=bT-FOlIuOiBtOasuPB-p9887tkpEqvQUJBgn1Q45ph0,15912
|
|
155
155
|
verifiers/v1/serve/server.py,sha256=i6XrY_PMAapkrP54tYX8-K6iGmOmrR7BbQ-3Qhn3w4s,9885
|
|
@@ -190,8 +190,8 @@ verifiers/v1/utils/prime.py,sha256=UTYRjp9cbjNb6CVmBHda-1wWZAIIfxNOmTyNuT7_wL4,9
|
|
|
190
190
|
verifiers/v1/utils/retries.py,sha256=Y2ZgrAjn-qNkRKZP_RVNL_7EK0iaRcZeCa404lpGYi4,5417
|
|
191
191
|
verifiers/v1/utils/score.py,sha256=493yJVMw8teCu9JxapxMFPFzI0hNUqdo0Y2nGW4kckk,6200
|
|
192
192
|
verifiers/v1/utils/version.py,sha256=-obEo_-l9-D8FLef4hYxncOe-uJpxrM1g2Hig_37Sgs,1607
|
|
193
|
-
verifiers-0.3.2.
|
|
194
|
-
verifiers-0.3.2.
|
|
195
|
-
verifiers-0.3.2.
|
|
196
|
-
verifiers-0.3.2.
|
|
197
|
-
verifiers-0.3.2.
|
|
193
|
+
verifiers-0.3.2.dev103.dist-info/METADATA,sha256=rKTglWoohmp1KBjJ4g2mXl2VqywfDsMGbK-PSv2ATR8,4238
|
|
194
|
+
verifiers-0.3.2.dev103.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
195
|
+
verifiers-0.3.2.dev103.dist-info/entry_points.txt,sha256=iugElcdWPKbQM7uFF0lZ8iUpHsNr17-BwEAAjJWxV3U,259
|
|
196
|
+
verifiers-0.3.2.dev103.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
|
|
197
|
+
verifiers-0.3.2.dev103.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|