nemo_gym.chat_streaming
nemo_gym.chat_streaming
Streaming Chat Completions-dialect support shared by every Gym model server.
Blackbox harnesses that speak the OpenAI Chat Completions API over SSE (e.g. the OpenClaw
agent PinchBench runs) send requests the strict NeMoGymChatCompletionCreateParamsNonStreaming
model rejects: a stream: true flag (its stream field is typed Literal[False], since a
Gym model server calls its backend non-streaming and buffers the whole response) plus a
stream_options block, which is only meaningful alongside stream: true.
A Gym model server can still serve these clients by computing the complete Chat Completion with its existing non-streaming backend call and re-emitting it as an SSE stream. This module provides:
- the request-side sanitizer that maps the streaming wire body onto the strict params shape
(drops
stream/stream_options, remembers whether usage was requested); - the response-side synthesizer that re-emits a complete
NeMoGymChatCompletionas thechat.completion.chunkSSE sequence a streaming client expects, terminated bydata: [DONE].
Only the SSE envelope is synthesized — there is no true token-by-token streaming. The backend
call completes before the first byte is emitted, so the model server’s retry and
error-normalization behavior is fully preserved on this path. This path is intended for eval-only
streaming clients: token ids and logprobs from the backend response are not carried in the
chat.completion.chunk schema, and a client that does not set stream_options.include_usage
gets no usage chunk, so a model-call record reconstructed from this stream will lack token counts.
Module Contents
Functions
Data
API
Yield the chat.completion.chunk choice deltas for one completed choice.
A role delta opens the choice; reasoning, content, and tool-call deltas follow (each emitted
only when present); a terminal delta carries the finish_reason. Splitting the message this
way keeps every field a client tracks (role, reasoning, content, tool-call name/arguments,
finish reason) in the delta position that client expects, even though it is a single logical
chunk sequence rather than incremental tokens.
Build one chat.completion.chunk object sharing the completion’s id/created/model.
Whether the client asked for a terminal usage chunk (stream_options.include_usage).
Map a streaming-dialect chat body onto the strict non-streaming params shape.
Returns the cleaned body dict (ready for NeMoGymChatCompletionCreateParamsNonStreaming
validation) and whether a terminal usage chunk was requested via
stream_options.include_usage.
stream and stream_options are removed: the params model’s stream field is typed
Literal[False], and stream_options is only meaningful with stream: true, so it has
no effect on the non-streaming backend call. Remaining fields are filtered to the known params
fields, so a harness’s extra bookkeeping never reaches the backend.
Re-emit a complete Chat Completion object as a chat.completion.chunk SSE stream.
Emits, per choice, a role chunk -> optional reasoning/content/tool-call chunks -> a terminal
chunk carrying finish_reason. When include_usage is set and the completion reports
usage, a final choices: [] chunk carries the usage block (OpenAI’s contract). The stream
always ends with the data: [DONE] sentinel streaming clients treat as terminal.