Why SSE over WebSockets
SSE (Server-Sent Events) is one-way: server pushes, client listens. WebSockets are two-way. For a chat where the client sends one prompt and the server streams back tokens, SSE is the right shape — simpler, plays nicer with HTTP middleware, and reconnects are free.
The wire format
SSE is just text/event-stream over HTTP. Each event is data: <payload>\n\n. The browser's EventSource API or any fetch + ReadableStream reader can parse it.
Async generator → SSE
FastAPI's StreamingResponse takes any iterable. An async generator yields strings; FastAPI flushes each one to the network. The event loop stays free to do other work between yields.
Write before show: Every chunk yielded to the browser must already be persisted in the JSONL ground truth. If the JSONL append fails, we don't yield. This is what 'never present broken chat to Dad' means in code (Truth track, lesson 1).