Server-Sent Events (SSE) streaming lets the model’s response arrive incrementally — word by word, tool-call fragment by fragment — instead of waiting for the full completion.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/phpaisdk/openai-compatible/llms.txt
Use this file to discover all available pages before exploring further.
ChatStreamParser::parse() converts the raw SSE event stream from any OpenAI-compatible provider into a sequence of strongly-typed StreamPart objects that your application can process without touching the wire format directly.
Enabling streaming in the request
Passstream: true to ChatRequestBuilder::build(). The builder automatically appends stream_options: {include_usage: true} so token usage is available in the final event rather than being discarded.
Parsing the stream
ChatStreamParser::parse() accepts an iterable of raw SSE events and returns a Generator of StreamPart objects. Each event is a two-key array with event (nullable string) and data (the raw SSE data line string).
The
[DONE] sentinel that OpenAI-compatible providers send at the end of the stream is handled automatically. The parser skips it silently — you never need to check for it in your foreach loop.StreamPart types
The generator emits parts in a defined order. Understanding each type lets you build rich streaming UIs, accumulate tool-call arguments progressively, and surface reasoning traces.ProviderMetadataPart — response-level metadata
ProviderMetadataPart — response-level metadata
Emitted as soon as the first event that contains response-level fields (
id, object, created, model, system_fingerprint, service_tier) is parsed. This part arrives before any text or tool-call parts.A second ProviderMetadataPart is emitted when the choice-level finish_reason is encountered, carrying choice_index and choice_finish_reason.TextDeltaPart — incremental text content
TextDeltaPart — incremental text content
Emitted for every SSE event that contains a non-empty
delta.content string. Stream these to the user as they arrive for the smoothest experience.ReasoningDeltaPart — incremental reasoning content
ReasoningDeltaPart — incremental reasoning content
Emitted when the delta contains a
reasoning_content or reasoning key (the parser checks both, preferring reasoning_content). Useful for models that expose chain-of-thought tokens separately from the final response.ToolCallStartPart — tool call slot opened
ToolCallStartPart — tool call slot opened
Emitted exactly once per tool-call slot (identified by
index) when the first event for that slot arrives and includes a call id. Gives you the slot index, the call ID, and the function name up front.ToolCallDeltaPart — incremental JSON arguments
ToolCallDeltaPart — incremental JSON arguments
Emitted for every event that delivers a non-empty
function.arguments fragment for a given slot. The argsJson field is a raw JSON string fragment — the full JSON is only valid once all deltas for the slot are concatenated (which StreamState does for you).FinishPart — stream complete
FinishPart — stream complete
Always emitted last, after all events have been consumed. Carries the normalized finish reason and the final usage figures (populated from the last
usage event, which stream_options: {include_usage: true} guarantees).Accumulating state with StreamState
Rather than matching each part type manually, pass every part toStreamState::record(). After the loop, the state object exposes the fully assembled text, tool calls, usage, and metadata.
Full streaming tool-call example
The following example is drawn directly fromChatWireFormatTest.php and shows the complete SSE event sequence for a streamed tool call, including fragmented JSON arguments: