DeepSeek V4.1 Flash is now available on Netra

Explore model
Netra Runtime

API REFERENCE

Streaming

Consume incremental output and handle a stream that ends with an error.

Overview

For Chat Completions, set stream: true to receive Server-Sent Events. Messages and Responses use different event formats described in their guides. Each data: event carries a JSON chunk, and a normal stream ends with data: [DONE]. Network reads do not necessarily align with complete events; use an SDK or an SSE parser.

import os
import sys
from openai import OpenAI

client = OpenAI(
    base_url="https://api.netraruntime.com/v1",
    api_key=os.environ["NETRA_API_KEY"],
    max_retries=0,
)
with client.chat.completions.create(
    model=os.environ["NETRA_MODEL"],
    messages=[{"role": "user", "content": "Explain tracing briefly."}],
    max_tokens=256,
    stream=True,
    stream_options={"include_usage": True},
) as stream:
    reasoning_details = []
    for chunk in stream:
        # Usage may arrive with empty choices; inspect it separately.
        if chunk.usage is not None:
            details = getattr(chunk.usage, "completion_tokens_details", None)
            count = getattr(details, "reasoning_tokens", None)
            if count is not None:
                print(f"Reasoning tokens: {count}", file=sys.stderr)
        if chunk.choices:
            delta = chunk.choices[0].delta
            details = getattr(delta, "reasoning_details", None)
            if details is not None:
                reasoning_details.extend(details)
            if details:
                reasoning = "".join(
                    d.get("text", "") if d.get("type") == "reasoning.text"
                    else d.get("summary", "") if d.get("type") == "reasoning.summary"
                    else "" for d in details
                )
            else:
                reasoning = getattr(delta, "reasoning", None) or getattr(delta, "reasoning_content", None)
            if reasoning:
                print(reasoning, end="", flush=True, file=sys.stderr)
            text = delta.content
            if text:
                print(text, end="", flush=True)
print()

Chunks can contain role metadata, empty choices, reasoning deltas, tool-call fragments, usage, or finish information rather than display text. Accumulate content, reasoning, and tool arguments separately. choices[0].delta.reasoning can arrive while delta.content is null. The legacy reasoning_content alias can appear in the same chunk. Render one channel: nonempty reasoning_details first, otherwise reasoning, otherwise reasoning_content. Do not concatenate these aliases. Retain every detail object in receive order for continuation, including empty arrays when supplied. Display text/summary only; encrypted data and signatures are opaque. A provider may expose final usage when supported, but it is not guaranteed on every chunk or stream.

With stream_options: {"include_usage": true}, a supported provider can report final usage in an event such as this illustrative example:

{
  "choices": [],
  "usage": {
    "prompt_tokens": 30,
    "completion_tokens": 12,
    "completion_tokens_details": { "reasoning_tokens": 8 },
    "total_tokens": 42
  }
}

Read usage.completion_tokens_details.reasoning_tokens independently of choices and display deltas. It is a subset of completion tokens, including when reasoning output is excluded; do not add it to the completion total or infer it from text length. Nested counts take precedence over the compatible flat usage.reasoning_tokens alias. Missing provider counts stay absent, and an interrupted stream may never deliver final usage. Do not sum repeated cumulative usage snapshots as if they were per-chunk token counts.

Once streaming headers have been sent, a later failure cannot change the original HTTP status. A balance exhaustion can appear as a terminal error event followed by [DONE]. Treat an error event or unexpected connection closure as an incomplete answer even when the initial HTTP status was 200. Preserve already received output and record the request ID for investigation.

Cancelling or disconnecting does not guarantee zero cost; output already generated or delivered can still be settled. A retry can start another billable generation. For command-line inspection, add -N to cURL to disable its output buffering. For hosted clients, ensure your proxy permits streaming and has a timeout appropriate for generation.

Search documentation

Search across all documentation.

Up and down arrows to navigate

Enter to open

esc to close