Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions verifiers/v1/clients/openai.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"""OpenAI-compatible chat-completions client.

Distilled from v1's 545-line client: message<->wire translation, tool schemas,
best-effort reasoning_content. Token-id/logprob/routed-experts/audio handling is
dropped (training-only). This is the one place raw provider dicts cross into our
typed `Response`.
best-effort reasoning_content. Sampling args pass straight through; when the
response carries vLLM's token ids + sampling logprobs (the caller asked for
`logprobs` and `return_token_ids`), we parse them into the response's `tokens`
so MITO training needs no renderer. Routed-experts/audio handling stays dropped.
This is the one place raw provider dicts cross into our typed `Response`.
"""

from openai import AsyncOpenAI, OpenAIError
Expand All @@ -19,6 +21,7 @@
SamplingConfig,
Tool,
ToolCall,
TurnTokens,
Usage,
)

Expand Down Expand Up @@ -58,6 +61,25 @@ def tool_to_wire(tool: Tool) -> dict:
return {"type": "function", "function": function}


def tokens_from_wire(completion, choice) -> TurnTokens | None:
"""Parse vLLM's token ids + sampling logprobs into `TurnTokens`, for training.

vLLM surfaces the completion ids on the choice (`return_token_ids`), the prompt
ids on the completion, and the sampled logprobs as one `logprobs.content` entry
per generated token (`logprobs=True`). All are absent on providers that don't
return them, so this is best-effort: no completion ids means no `tokens`.
"""
completion_ids = getattr(choice, "token_ids", None)
if not completion_ids:
return None
content = choice.logprobs.content if choice.logprobs else None
return TurnTokens(
prompt_ids=list(getattr(completion, "prompt_token_ids", None) or []),
completion_ids=list(completion_ids),
completion_logprobs=[lp.logprob for lp in content] if content else [],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Partial tokens without prompt ids

Medium Severity

tokens_from_wire builds TurnTokens whenever choice.token_ids is present, but missing completion.prompt_token_ids becomes an empty prompt_ids list instead of skipping tokens. Downstream MITO training can treat the rollout as on-policy while the prompt side is empty.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 89368c8. Configure here.

)


def response_from_wire(completion) -> Response:
choice = completion.choices[0]
message = choice.message
Expand Down Expand Up @@ -87,6 +109,7 @@ def response_from_wire(completion) -> Response:
),
finish_reason=finish,
usage=usage,
tokens=tokens_from_wire(completion, choice),
)


Expand Down
7 changes: 4 additions & 3 deletions verifiers/v1/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,8 +97,9 @@ def total_tokens(self) -> int:


class TurnTokens(StrictBaseModel):
"""Token ids + sampling logprobs for one response, for training. Populated only
by the renderer client (which tokenizes client-side); None otherwise."""
"""Token ids + sampling logprobs for one response, for training. Populated by the
renderer client (client-side tokenization) or the chat client (parsed from vLLM's
token ids); None when the provider returns neither."""

prompt_ids: list[int] = Field(default_factory=list)
completion_ids: list[int] = Field(default_factory=list)
Expand All @@ -115,7 +116,7 @@ class Response(StrictBaseModel):
finish_reason: FinishReason
usage: Usage | None = None
tokens: TurnTokens | None = None
"""Client-side token ids + logprobs (renderer client only)."""
"""Token ids + logprobs for training (renderer client, or chat client via vLLM)."""


# --- sampling -----------------------------------------------------------------
Expand Down
Loading