Each LangGraph stream(...) iteration yields either a (node_name, state) tuple (state transition) or a dict (token chunk). Your async generator maps tuples to {"type": "status", "step": node_name} and state["final_response"] or human/escalation branches to {"type": "response"}, then yields them as `data: JSON-payload
`. The browser keeps a single EventSource and gets live status + final answer.
/chat/stream endpoint: agent = AgentCoordinator.stream_message(); generator yields SSE-wrapped events.
ContextVar bridges log calls inside the agent notebook to the same SSE stream — logger.info("step X") appears live.
ESC_PLACEHOLDER: {type: "escalation", payload: ...} so the UI can render a “human needed” card.
agent.stream -> queue -> SSE -> browser EventSource
(node tuples / chunks -> status or response events)
SSE is the lightweight, browser-native way to stream an agent — no WebSockets needed.