Four things cause this, and only the last one is on our side.
stream is not set. Without "stream": true the reply is generated in full and arrives in one piece — on a long answer that is indistinguishable from a hang.
The response is being read whole. response.json() or response.text() waits for the stream to finish before returning anything. Iterate it instead; both the OpenAI SDK and ours do that for you. With curl, pass -N.
Nothing has happened yet. The first chunk can take several seconds on a large model. That is time to first token, not a stall — the connection is open and the answer is on its way.
Something in between is buffering. We send x-accel-buffering: no, which most proxies honour, but a corporate proxy or a serverless platform that ignores it will hold the whole response until the end.
Every stream ends the same way: a usage chunk carrying credits_used, then data: [DONE]. If you never see [DONE], the connection was cut mid-stream rather than the model stopping — retry, and tell us if it keeps happening.