# Event protocol Typed in `packages/events/src/index.ts`. Persisted per session with a monotonic `seq`; streamed over SSE at `GET /api/research/:id/stream`. ## Transport - `id:` field = `seq` → browsers resend `Last-Event-ID` on reconnect; the server replays from that position. `?from=0` replays a full session (used by the event-sourced UI). - Heartbeat comment every 15s keeps proxies from idling out the connection. - `event: end` closes the stream once the session is terminal and fully delivered. - SSE responses set `Cache-Control: no-cache, no-transform` and `X-Accel-Buffering: no` so the ngrok/proxy chain doesn't buffer. ## Event types | Type | Meaning | |---|---| | `session.started` / `session.status` / `session.completed` / `session.failed` | lifecycle | | `plan.updated` | objectives set/revised (with public reason) | | `thought` | public narration — never hidden chain of thought | | `action.started` / `action.completed` | search/fetch with latency + outcome | | `source.added` / `source.updated` | source lifecycle | | `evidence.added` | quote + stance + source context | | `claim.added` / `claim.updated` | hypothesis lifecycle, confidence changes | | `contradiction.added` | surfaced disagreement | | `budget.updated` | usage vs limits after each search/fetch | | `synthesis.started` | answer writing begins | | `answer.delta` / `answer.completed` | streaming final answer; completed carries the citation map |