verifiers 0.3.2.dev85__py3-none-any.whl → 0.3.2.dev87__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/dialects/chat.py +7 -2
- verifiers/v1/harnesses/utils/core.py +25 -2
- verifiers/v1/interception/server.py +29 -11
- verifiers/v1/session.py +2 -1
- {verifiers-0.3.2.dev85.dist-info → verifiers-0.3.2.dev87.dist-info}/METADATA +1 -1
- {verifiers-0.3.2.dev85.dist-info → verifiers-0.3.2.dev87.dist-info}/RECORD +9 -9
- {verifiers-0.3.2.dev85.dist-info → verifiers-0.3.2.dev87.dist-info}/WHEEL +0 -0
- {verifiers-0.3.2.dev85.dist-info → verifiers-0.3.2.dev87.dist-info}/entry_points.txt +0 -0
- {verifiers-0.3.2.dev85.dist-info → verifiers-0.3.2.dev87.dist-info}/licenses/LICENSE +0 -0
verifiers/v1/dialects/chat.py
CHANGED
|
@@ -549,14 +549,19 @@ class ChatDialect(Dialect[ChatCompletion]):
|
|
|
549
549
|
|
|
550
550
|
def stream_events(self, raw: dict) -> list[bytes]:
|
|
551
551
|
choice = (raw.get("choices") or [{}])[0]
|
|
552
|
+
message = dict(choice.get("message") or {"role": "assistant", "content": ""})
|
|
553
|
+
if message.get("tool_calls"):
|
|
554
|
+
message["tool_calls"] = [
|
|
555
|
+
{**call, "index": index}
|
|
556
|
+
for index, call in enumerate(message["tool_calls"])
|
|
557
|
+
]
|
|
552
558
|
chunk = {
|
|
553
559
|
**{key: value for key, value in raw.items() if key != "choices"},
|
|
554
560
|
"object": "chat.completion.chunk",
|
|
555
561
|
"choices": [
|
|
556
562
|
{
|
|
557
563
|
"index": 0,
|
|
558
|
-
"delta":
|
|
559
|
-
or {"role": "assistant", "content": ""},
|
|
564
|
+
"delta": message,
|
|
560
565
|
"finish_reason": choice.get("finish_reason"),
|
|
561
566
|
}
|
|
562
567
|
],
|
|
@@ -9,7 +9,8 @@ from pathlib import Path
|
|
|
9
9
|
from typing import TYPE_CHECKING
|
|
10
10
|
|
|
11
11
|
import httpx
|
|
12
|
-
from openai import APIStatusError, AsyncOpenAI
|
|
12
|
+
from openai import APIStatusError, AsyncOpenAI, omit
|
|
13
|
+
from openai.lib.streaming.chat import AsyncChatCompletionStream
|
|
13
14
|
|
|
14
15
|
if TYPE_CHECKING:
|
|
15
16
|
# The harness bundles this module into the generated script before execution.
|
|
@@ -191,7 +192,29 @@ async def chat(
|
|
|
191
192
|
kwargs = {"model": model, "messages": messages, "tools": tools or None}
|
|
192
193
|
if tools and tool_choice is not None:
|
|
193
194
|
kwargs["tool_choice"] = tool_choice
|
|
194
|
-
|
|
195
|
+
raw_stream = await client.chat.completions.create(
|
|
196
|
+
**kwargs, stream=True, stream_options={"include_usage": True}
|
|
197
|
+
)
|
|
198
|
+
# Accumulate native deltas without auto-parsing tool arguments or treating
|
|
199
|
+
# finish_reason="length" as an exception: compaction owns that decision.
|
|
200
|
+
async with AsyncChatCompletionStream(
|
|
201
|
+
raw_stream=raw_stream, response_format=omit, input_tools=[]
|
|
202
|
+
) as response:
|
|
203
|
+
completion = None
|
|
204
|
+
async for event in response:
|
|
205
|
+
if event.type == "chunk":
|
|
206
|
+
completion = event.snapshot
|
|
207
|
+
if (
|
|
208
|
+
completion is None
|
|
209
|
+
or not completion.choices
|
|
210
|
+
or any(choice.finish_reason is None for choice in completion.choices)
|
|
211
|
+
):
|
|
212
|
+
raise RuntimeError("model stream ended before a completion finished")
|
|
213
|
+
for choice in completion.choices:
|
|
214
|
+
# Some providers repeat the role in each delta. The SDK concatenates
|
|
215
|
+
# these strings, but the role is metadata, not incremental content.
|
|
216
|
+
choice.message.role = "assistant"
|
|
217
|
+
return completion
|
|
195
218
|
|
|
196
219
|
|
|
197
220
|
async def run_tool_hook(
|
|
@@ -41,7 +41,11 @@ from pydantic_core import PydanticSerializationError, from_json, to_json
|
|
|
41
41
|
from verifiers.v1 import graph
|
|
42
42
|
from verifiers.v1.clients import Client, resolve_client
|
|
43
43
|
from verifiers.v1.clients.base import join_url
|
|
44
|
-
from verifiers.v1.configs.client import
|
|
44
|
+
from verifiers.v1.configs.client import (
|
|
45
|
+
BaseClientConfig,
|
|
46
|
+
TrainClientConfig,
|
|
47
|
+
resolve_api_key,
|
|
48
|
+
)
|
|
45
49
|
from verifiers.v1.dialects import DIALECTS, Dialect
|
|
46
50
|
from verifiers.v1.dialects.base import (
|
|
47
51
|
PROVIDER_CAPABILITY_POLICY_CODE,
|
|
@@ -127,15 +131,18 @@ def _capture_response(response: web.Response) -> ReplayResponse:
|
|
|
127
131
|
data = bytes(body)
|
|
128
132
|
else:
|
|
129
133
|
raise TypeError("coalesced interception responses must have a byte body")
|
|
130
|
-
return ReplayResponse(
|
|
134
|
+
return ReplayResponse(
|
|
135
|
+
status=response.status,
|
|
136
|
+
body=data,
|
|
137
|
+
content_type=response.headers["Content-Type"],
|
|
138
|
+
)
|
|
131
139
|
|
|
132
140
|
|
|
133
141
|
def _replay_response(response: ReplayResponse) -> web.Response:
|
|
134
142
|
return web.Response(
|
|
135
143
|
body=response.body,
|
|
136
144
|
status=response.status,
|
|
137
|
-
|
|
138
|
-
charset="utf-8",
|
|
145
|
+
headers={"Content-Type": response.content_type},
|
|
139
146
|
)
|
|
140
147
|
|
|
141
148
|
|
|
@@ -492,7 +499,10 @@ class InterceptionServer(Interception):
|
|
|
492
499
|
body = json.loads(raw)
|
|
493
500
|
body = dialect.apply_overrides(body, session.ctx.model, session.ctx.sampling)
|
|
494
501
|
streaming = dialect.streaming(body)
|
|
495
|
-
|
|
502
|
+
relay_streaming = streaming and not isinstance(
|
|
503
|
+
session.ctx.client, TrainClientConfig
|
|
504
|
+
)
|
|
505
|
+
req_hash = await _request_digest(raw) if not relay_streaming else b""
|
|
496
506
|
# Keep `read()` for aiohttp's size guard, then release its cache and our local
|
|
497
507
|
# alias after parsing so the wire body does not survive model inference.
|
|
498
508
|
request._read_bytes = None
|
|
@@ -507,7 +517,7 @@ class InterceptionServer(Interception):
|
|
|
507
517
|
session.trace.id,
|
|
508
518
|
streaming,
|
|
509
519
|
)
|
|
510
|
-
# Graph atomicity under retries: one logical
|
|
520
|
+
# Graph atomicity under retries: one logical buffered call must commit at most
|
|
511
521
|
# one turn. An explicit key identifies that call directly; otherwise only the SDK's
|
|
512
522
|
# retry marker activates body-digest replay, since an unmarked repeated body can be a
|
|
513
523
|
# legitimate later turn.
|
|
@@ -517,14 +527,14 @@ class InterceptionServer(Interception):
|
|
|
517
527
|
replay_key: str | None = None
|
|
518
528
|
binding = (request.path, req_hash)
|
|
519
529
|
if idempotency_key:
|
|
520
|
-
if
|
|
530
|
+
if relay_streaming and acp is None:
|
|
521
531
|
return web.json_response(
|
|
522
532
|
dialect.error_body(
|
|
523
533
|
"Idempotency-Key is not supported for streaming requests"
|
|
524
534
|
),
|
|
525
535
|
status=400,
|
|
526
536
|
)
|
|
527
|
-
if not
|
|
537
|
+
if not relay_streaming:
|
|
528
538
|
replay_key = f"explicit:{idempotency_key}"
|
|
529
539
|
# This key identifies the harness-to-interception hop. The server owns its
|
|
530
540
|
# replay semantics, and the body has since been rewritten with rollout model
|
|
@@ -534,7 +544,7 @@ class InterceptionServer(Interception):
|
|
|
534
544
|
for name, value in upstream_headers.items()
|
|
535
545
|
if name.lower() != IDEMPOTENCY_KEY_HEADER.lower()
|
|
536
546
|
}
|
|
537
|
-
elif not
|
|
547
|
+
elif not relay_streaming:
|
|
538
548
|
replay_key = f"retry:{request.path}:{req_hash.hex()}"
|
|
539
549
|
|
|
540
550
|
if replay_key is not None:
|
|
@@ -648,7 +658,7 @@ class InterceptionServer(Interception):
|
|
|
648
658
|
return self._fail(session, dialect, error)
|
|
649
659
|
|
|
650
660
|
inspect_response = bool(session.response_interceptors or session.response_stops)
|
|
651
|
-
if
|
|
661
|
+
if relay_streaming:
|
|
652
662
|
return await self._stream(
|
|
653
663
|
request,
|
|
654
664
|
session,
|
|
@@ -663,7 +673,15 @@ class InterceptionServer(Interception):
|
|
|
663
673
|
)
|
|
664
674
|
|
|
665
675
|
def serve(response: Response) -> web.Response:
|
|
666
|
-
|
|
676
|
+
if streaming:
|
|
677
|
+
# Training generates a complete response with token metadata.
|
|
678
|
+
# Commit it through the normal path, then frame it for SSE clients.
|
|
679
|
+
served = web.Response(
|
|
680
|
+
body=b"".join(dialect.stream_events(response.raw or {})),
|
|
681
|
+
content_type="text/event-stream",
|
|
682
|
+
)
|
|
683
|
+
else:
|
|
684
|
+
served = _completion_response(response.raw)
|
|
667
685
|
if idempotent is not None:
|
|
668
686
|
idempotent.response = _capture_response(served)
|
|
669
687
|
idempotent.completed_at = time.monotonic()
|
verifiers/v1/session.py
CHANGED
|
@@ -96,7 +96,7 @@ class RolloutLimits:
|
|
|
96
96
|
|
|
97
97
|
@dataclass
|
|
98
98
|
class IdempotentRequest:
|
|
99
|
-
"""One
|
|
99
|
+
"""One buffered model request shared by its original call and retries."""
|
|
100
100
|
|
|
101
101
|
binding: tuple[str, bytes]
|
|
102
102
|
response: "ReplayResponse | None" = None
|
|
@@ -110,6 +110,7 @@ class ReplayResponse:
|
|
|
110
110
|
|
|
111
111
|
status: int
|
|
112
112
|
body: bytes
|
|
113
|
+
content_type: str
|
|
113
114
|
|
|
114
115
|
|
|
115
116
|
@dataclass
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: verifiers
|
|
3
|
-
Version: 0.3.2.
|
|
3
|
+
Version: 0.3.2.dev87
|
|
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
|
|
@@ -10,7 +10,7 @@ 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=SvMgs7YBNjiftp4vlGVBMEseUsJs1h7qrqAlxmWaNwY,23987
|
|
12
12
|
verifiers/v1/semantic.py,sha256=VQ_buw6Ya6QtRoh_fiYI5Avs5RmIQCfWH0H0bQc4aoc,4704
|
|
13
|
-
verifiers/v1/session.py,sha256=
|
|
13
|
+
verifiers/v1/session.py,sha256=uwDcF7IxT6wVrfdMC34rEs-nAYxfsf6qxZV2qUFx8qE,18882
|
|
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
|
|
@@ -62,7 +62,7 @@ verifiers/v1/configs/cli/validate.py,sha256=NXQ9KvhGLODLrg1fs3Jn-SOq1hhPxauVWiPS
|
|
|
62
62
|
verifiers/v1/dialects/__init__.py,sha256=MNOYM2NdTlSxGK4VtoEjMtD5zya2MpjPDX5jMvZUWEo,736
|
|
63
63
|
verifiers/v1/dialects/anthropic.py,sha256=abwcKRsKkgfgLSuntxBMdL03enG7roRdGoHTYfswafM,26887
|
|
64
64
|
verifiers/v1/dialects/base.py,sha256=pcFqWXSl50VtMuzcY5cyhsc4WpKCM5wT-tskTFZV7CM,12203
|
|
65
|
-
verifiers/v1/dialects/chat.py,sha256=
|
|
65
|
+
verifiers/v1/dialects/chat.py,sha256=bHH_WuSlx3s0bgbFNTthb9MwLtQiT9WqMHmN0X4muwM,24092
|
|
66
66
|
verifiers/v1/dialects/responses.py,sha256=FRQXRubijMG7VuqW_I7ex2DnEzOjuZxwxATy-loEkm0,29254
|
|
67
67
|
verifiers/v1/envs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
68
68
|
verifiers/v1/envs/agentic_judge/__init__.py,sha256=LfEcRHLG_siKzhzWmODDXWSLpLgfum3UFdQDK9XG0gk,325
|
|
@@ -118,14 +118,14 @@ verifiers/v1/harnesses/terminus_2/harness.py,sha256=DMTY1bzvydyjHqzmvBSBGKJsmUzY
|
|
|
118
118
|
verifiers/v1/harnesses/terminus_2/program.py,sha256=X8MZdyItU3gbXGXnGOlJ9LWcUTnqIDaxlhkZvoRiqKY,2703
|
|
119
119
|
verifiers/v1/harnesses/utils/__init__.py,sha256=eTS-Ft2HwoLiYn5u1t_KueLmaZB_W12cdYmcVsE-G5A,364
|
|
120
120
|
verifiers/v1/harnesses/utils/compaction.py,sha256=DeY6CYLEsv7-vJm26sT2mRaPHu3W2ywiZhvFr_pi6Hg,10495
|
|
121
|
-
verifiers/v1/harnesses/utils/core.py,sha256=
|
|
121
|
+
verifiers/v1/harnesses/utils/core.py,sha256=UWcpglvx2sLtvqYZTO4NEMYwwSNeLHSaAcvbIA60Xzo,16004
|
|
122
122
|
verifiers/v1/harnesses/utils/install.py,sha256=BDkkUVZ1brSzCrbQOvMO5mVIE2DsV2pE7rTC5yROYUw,2992
|
|
123
123
|
verifiers/v1/harnesses/utils/launch.py,sha256=RqPuUY-kT2XVuLSGtXW7kRQEaP-o2KzkiJ7vcoo2neM,2883
|
|
124
124
|
verifiers/v1/harnesses/utils/mcp.py,sha256=oNhKfLjAW-wScJcDIsW_HfuvKY-JkaGBBZrRLqgRK1g,7355
|
|
125
125
|
verifiers/v1/interception/__init__.py,sha256=5Kvo7tcBUVaa65s9A1NiOH3CPpzw-P5btXwxB4Nbbvs,4251
|
|
126
126
|
verifiers/v1/interception/base.py,sha256=Mg16Y104lyZilF9shdivdqYoqz4OYp978i_myyrulu8,2529
|
|
127
127
|
verifiers/v1/interception/pool.py,sha256=sk_zcdTV8EVRuzqlYMXxon_42tSDAlFvwcyOO2EF7hw,6473
|
|
128
|
-
verifiers/v1/interception/server.py,sha256=
|
|
128
|
+
verifiers/v1/interception/server.py,sha256=P-gGTVHP0KyjNfFO2ikQ-_Rnp6x0yhelhEnY4g7jOIo,52919
|
|
129
129
|
verifiers/v1/interception/tool.py,sha256=ZyZPxLYM_HsGkz-ZbCREQVGtiKZK9lQLChBNF_bBuuc,259
|
|
130
130
|
verifiers/v1/interception/tunnel/__init__.py,sha256=eVNZJszj6myrKhx9jmJz7VRd9qlfj0AUvUZwI2bXEj8,893
|
|
131
131
|
verifiers/v1/interception/tunnel/base.py,sha256=DZB6uPLwM4Qy7n7m0vKeyg-Px87MhsmpYTpe2vpPEng,1998
|
|
@@ -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.dev87.dist-info/METADATA,sha256=g8gNfmMA2v1sU8Jl2cyl9WGSJ5nZXJPhW2f5fQy-5n0,4237
|
|
194
|
+
verifiers-0.3.2.dev87.dist-info/WHEEL,sha256=zOwg4jB6zX2kU910N-cMawjivD6tO8NEWvE12je1bVk,87
|
|
195
|
+
verifiers-0.3.2.dev87.dist-info/entry_points.txt,sha256=uqQje0TMsr7k6nXlWxlPs13Si0evb3pVCEDF6c-YL80,241
|
|
196
|
+
verifiers-0.3.2.dev87.dist-info/licenses/LICENSE,sha256=v0RrUsdV3IDoZhrRce297IXS3xMHNJ-_LdLpFAUWb9k,1072
|
|
197
|
+
verifiers-0.3.2.dev87.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|