# `SuperPi.Event.Renderer`
[🔗](https://github.com/oleksandr/super-pi-beam/blob/v0.1.0/lib/super_pi/event/renderer.ex#L1)

Turns `SuperPi.Event`s into the output of one protocol.

A renderer is a pure state machine, not a process. The transport process owns the socket and the
renderer owns only its projection state, so a renderer needs no socket to be tested. This is the
shape of `SuperPi.RPC.Server.handle_rpc_payload/2`, which is pure for the same reason.

Cross-event state is why `init/1` exists. AG-UI must open and close a text message around a run of
bare deltas, and ACP tracks a tool call from `pending` to `completed`.

    state = Renderer.OpenAI.init(id: "chatcmpl-1", model: "super-pi-code")
    {chunks, state} = Renderer.OpenAI.render(event, state)
    {tail, _state} = Renderer.OpenAI.flush(state)

| Renderer | Output per call |
|---|---|
| `SuperPi.Event.Renderer.OpenAI` | chat completion chunk maps |
| `SuperPi.Event.Renderer.RPC` | the wire map (identity) |
| `SuperPi.Event.Renderer.TUI` | terminal lines |
| `SuperPi.Event.Renderer.ACP` | `session/update` notification params |
| `SuperPi.Event.Renderer.AGUI` | AG-UI event maps |

# `flush`

```elixir
@callback flush(state :: term()) :: {[term()], term()}
```

Ends the stream: output that closes what is open. Returns the final output and state.

# `init`

```elixir
@callback init(opts :: keyword()) :: term()
```

Builds the initial state from options.

# `render`

```elixir
@callback render(SuperPi.Event.t(), state :: term()) :: {[term()], term()}
```

Renders one event. Returns the output items, possibly none, and the next state.

# `render_all`

```elixir
@spec render_all(module(), [SuperPi.Event.t()], keyword()) :: [term()]
```

Renders a list of events and flushes, for tests and for replay of a stored history.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
