A custom LogHandler that reads a ContextVar (request_id, user_id, agent_step, message) and forwards each emitted log record to a per-request asyncio.Queue. The same queue also carries SSE events to the browser; the consumer stream merges them into one wire.
SSELogHandler.emit(record): queue.put_nowait({”type”: “log”, "record": ...});
ContextVar ensures the right request_id / agent_step is in scope per async task.
The browser sees logs and events interleaved chronologically, no need for a separate log endpoint.
logger.info(...) -> SSELogHandler -> per-request queue
queue -> async generator -> SSE events
(logs + agent events in one browser stream)
Streaming the same logs your SRE sees into the browser debug panel halves diagnosis time.