diff --git a/verifiers/v1/interception/server.py b/verifiers/v1/interception/server.py index 5aa94bb489..12f5a884a6 100644 --- a/verifiers/v1/interception/server.py +++ b/verifiers/v1/interception/server.py @@ -30,7 +30,7 @@ from aiohttp import web from pydantic import ValidationError -from pydantic_core import from_json +from pydantic_core import PydanticSerializationError, from_json, to_json from verifiers.v1.clients import RolloutContext from verifiers.v1.dialects import DIALECTS, Dialect @@ -60,6 +60,15 @@ _HOST = "127.0.0.1" +def _completion_response(completion: dict | None) -> web.Response: + """Serialize a model's JSON-native response without an intermediate string.""" + try: + body = to_json(completion, inf_nan_mode="constants") + except PydanticSerializationError: + return web.json_response(completion) + return web.Response(body=body, content_type="application/json", charset="utf-8") + + @dataclass(frozen=True) class RolloutLimits: """Per-rollout framework limits (None = no cap), checked before each turn is served. @@ -292,7 +301,7 @@ async def handle_request( return web.json_response( dialect.error_body(f"rollout stopped: {refused}"), status=400 ) - return web.json_response(completion) + return _completion_response(completion) turn = graph.prepare_turn(session.trace, prompt) session.error = None try: @@ -316,7 +325,7 @@ async def handle_request( dialect.error_body("rollout stopped: context_length"), status=400, ) - return web.json_response(completion) + return _completion_response(completion) except RolloutError as e: # Stash the real cause; the rollout re-raises it after the harness returns. Relay # the provider's status so the harness SDK retries 5xx/429 and not 4xx. @@ -351,7 +360,7 @@ async def handle_request( # Hand back to the program when the model wants a tool (the program runs it) or # when there's no user simulator to keep the conversation going. if response.message.tool_calls or session.user is None: - return web.json_response(completion) + return _completion_response(completion) try: user_messages = await session.user(response.message.content or "") except RolloutError as e: