# Streaming (/ro/docs/gateway/streaming)

Server-sent events pentru fiecare wire format și unde ajunge usage-ul de tokeni.

Setezi `stream: true` pe oricare dintre cele trei formate și gateway-ul răspunde cu `Content-Type: text/event-stream`. Frame-urile sunt separate de o linie goală; fiecare poartă o linie `data:` cu un payload JSON. Pot apărea comentarii keep-alive — sari liniile care nu încep cu `data:` (sau `event:` pentru Anthropic).

## OpenAI Chat Completions [#openai-chat-completions]

```bash
curl -N https://ai.codai.ro/v1/chat/completions \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "codai", "stream": true, "messages": [{ "role": "user", "content": "Numără până la trei." }] }'
```

```text
data: {"id":"chatcmpl_7d3c…","object":"chat.completion.chunk","created":1790000000,"model":"codai","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}

data: {"id":"chatcmpl_7d3c…","object":"chat.completion.chunk","created":1790000000,"model":"codai","choices":[{"index":0,"delta":{"content":"Unu"},"finish_reason":null}]}

data: {"id":"chatcmpl_7d3c…","object":"chat.completion.chunk","created":1790000000,"model":"codai","choices":[{"index":0,"delta":{"content":", doi, trei."},"finish_reason":null}]}

data: {"id":"chatcmpl_7d3c…","object":"chat.completion.chunk","created":1790000000,"model":"codai","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}

data: {"id":"chatcmpl_7d3c…","object":"chat.completion.chunk","created":1790000000,"model":"codai","choices":[],"usage":{"prompt_tokens":12,"completion_tokens":7,"total_tokens":19,"prompt_tokens_details":{"cached_tokens":0}}}

data: [DONE]
```

### Usage în chunk-ul final [#usage-în-chunk-ul-final]

Gateway-ul emite **mereu** un chunk terminal cu `choices` gol și un obiect `usage` înainte de `[DONE]`, indiferent dacă trimiți sau nu `stream_options: { include_usage: true }`. Să-l trimiți nu strică și îți ține codul portabil către OpenAI upstream. `usage.prompt_tokens_details.cached_tokens` este numărul de tokeni de prompt serviți din prompt cache.

### Tool calls într-un stream [#tool-calls-într-un-stream]

Tool calls sosesc pe bucăți: `id` și `function.name` întâi, apoi `function.arguments` adăugat peste multe delta-uri, cheiat după `index`. Concatenezi `arguments` per index până la `finish_reason: "tool_calls"`. [SDK-ul TypeScript](../sdks/typescript.mdx) face asta pentru tine și expune apelurile asamblate pe `stream.final`.

```text
data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"id":"call_ab12","type":"function","function":{"name":"get_weather","arguments":""}}]},"finish_reason":null}]}

data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"{\"city\":"}}]},"finish_reason":null}]}

data: {"choices":[{"index":0,"delta":{"tool_calls":[{"index":0,"function":{"arguments":"\"Cluj\"}"}}]},"finish_reason":null}]}

data: {"choices":[{"index":0,"delta":{},"finish_reason":"tool_calls"}]}
```

## Anthropic Messages [#anthropic-messages]

```bash
curl -N https://ai.codai.ro/v1/messages \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{ "model": "codai", "max_tokens": 256, "stream": true, "messages": [{ "role": "user", "content": "Numără până la trei." }] }'
```

```text
event: message_start
data: {"type":"message_start","message":{"id":"msg_01Xf…","type":"message","role":"assistant","model":"codai","content":[],"stop_reason":null,"usage":{"input_tokens":12,"output_tokens":1,"cache_read_input_tokens":0,"cache_creation_input_tokens":0}}}

event: content_block_start
data: {"type":"content_block_start","index":0,"content_block":{"type":"text","text":""}}

event: content_block_delta
data: {"type":"content_block_delta","index":0,"delta":{"type":"text_delta","text":"Unu, doi, trei."}}

event: content_block_stop
data: {"type":"content_block_stop","index":0}

event: message_delta
data: {"type":"message_delta","delta":{"stop_reason":"end_turn","stop_sequence":null},"usage":{"output_tokens":7}}

event: message_stop
data: {"type":"message_stop"}
```

Tokenii de input sunt finali în `message_start`; `message_delta.usage.output_tokens` este cumulativ — ultima valoare câștigă. Tool use face stream ca `content_block_start` cu `type: "tool_use"` urmat de delta-uri `input_json_delta`, exact ca la upstream.

## OpenAI Responses [#openai-responses]

```bash
curl -N https://ai.codai.ro/v1/responses \
  -H "Authorization: Bearer $CODAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "model": "codai", "stream": true, "input": "Numără până la trei." }'
```

```text
event: response.created
data: {"type":"response.created","response":{"id":"resp_9f1e…","object":"response","status":"in_progress"},"sequence_number":0}

event: response.output_text.delta
data: {"type":"response.output_text.delta","item_id":"msg_resp_9f1e…","delta":"Unu","sequence_number":1}

event: response.output_text.delta
data: {"type":"response.output_text.delta","item_id":"msg_resp_9f1e…","delta":", doi, trei.","sequence_number":2}

event: response.output_text.done
data: {"type":"response.output_text.done","item_id":"msg_resp_9f1e…","text":"Unu, doi, trei.","sequence_number":3}

event: response.completed
data: {"type":"response.completed","response":{"id":"resp_9f1e…","object":"response","status":"completed","output":[{"type":"message","id":"msg_resp_9f1e…","role":"assistant","status":"completed","content":[{"type":"output_text","text":"Unu, doi, trei.","annotations":[]}]}],"output_text":"Unu, doi, trei.","usage":{"input_tokens":12,"input_tokens_details":{"cached_tokens":0},"output_tokens":7,"total_tokens":19}},"sequence_number":4}
```

Apelurile de funcție sunt golite la final ca evenimente `response.output_item.done` cu elemente `type: "function_call"`, apoi incluse în `response.completed.output`. Usage există doar pe `response.completed`.

## Header-e pe un răspuns în stream [#header-e-pe-un-răspuns-în-stream]

Header-ele sunt trimise înaintea primului byte, așa că tot ce depinde de numărul final de tokeni nu poate fi încă exact:

| Header | Pe un stream |
| --- | --- |
| `x-codai-routed-to`, `x-codai-provider` | Cunoscute — ținta a fost aleasă înainte de dispatch. |
| `x-codai-trace-id` | Cunoscut — reflectă `X-Request-Id` al tău sau un id generat. |
| `x-codai-ai-generated`, `x-codai-generator` | Trimise mereu — `true` și `codai/<model upstream>` (marcaj de conținut generat de AI, AI Act UE, art. 50 alin. (2)). |
| `x-codai-cost-micro-usd` | Prezent doar când numărul de tokeni era cunoscut dinainte. |
| `x-codai-cost-estimate: pending` | Trimis în loc pe stream-urile native; cifra exactă e în `GET /v1/receipt` și în hub. |
| `x-codai-cache-read`, `x-codai-cache-write` | Setate când cifrele de cache erau cunoscute înaintea primului byte. |

## Sfaturi pentru clienți [#sfaturi-pentru-clienți]

- Folosești `curl -N` (sau modul fără buffering al clientului tău HTTP) — proxy-urile care fac buffering vor reține tot răspunsul.
- Tratezi `data: [DONE]` (Chat Completions), `message_stop` (Messages) sau `response.completed` (Responses) ca final. Nu te bazezi pe închiderea socket-ului.
- Dacă un stream se blochează după primul byte, gateway-ul îl închide cu un frame de stop curat și înregistrează tura ca blocată; reîncerci cu aceeași cerere — prompt caching face reîncercarea ieftină.
- Pentru browsere, politica CORS pe `/v1/*` expune header-ele `x-codai-*` și `x-ratelimit-*`, așa că `fetch` le poate citi.
