Streaming Events
When you request a streaming response, ai& streams the model’s SSE events unchanged and then appends a single trailer event carrying cost, request ID, and final usage.
OpenAI shape
Section titled “OpenAI shape”data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"delta":{"content":"Hel"}}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"delta":{"content":"lo"}}]}
data: {"id":"chatcmpl-...","object":"chat.completion.chunk","choices":[{"delta":{},"finish_reason":"stop"}],"usage":{"prompt_tokens":7,"completion_tokens":2,"total_tokens":9}}
data: [DONE]
event: aiand.metadatadata: {"request_id":"req-...","cost_usd":0.000018,"model":"..."}The aiand.metadata event is emitted after [DONE]. Robust clients should keep the connection open until the stream closes naturally.
Anthropic shape
Section titled “Anthropic shape”event: message_startdata: {"type":"message_start",...}
event: content_block_deltadata: {"type":"content_block_delta",...}
event: message_deltadata: {"type":"message_delta","usage":{"output_tokens":2}}
event: message_stopdata: {"type":"message_stop"}
event: aiand.metadatadata: {"request_id":"req-...","cost_usd":0.000018,"model":"..."}The trailer event
Section titled “The trailer event”| Field | Description |
|---|---|
request_id | Same as X-Request-ID header. |
cost_usd | Final cost in USD. |
model | Model that actually served the request. |
usage | (optional) Echo of the final usage block, for shapes that don’t emit it natively. |
Why a trailer event?
Section titled “Why a trailer event?”ai& never modifies the response body emitted by the model. Cost, request id, and final usage are delivered as a named SSE event after the terminal message, so the byte stream above the trailer is identical to what the source API would produce — the official OpenAI and Anthropic SDKs work without modification.