# `A2UIPhoenix.Live`
[🔗](https://github.com/a2ui-elixir/a2ui/blob/v0.1.1/umbrella/apps/a2ui_phoenix/lib/a2ui_phoenix/live.ex#L1)

Hosts an `A2UIPhoenix.Session` in a LiveView.

    def mount(_params, _session, socket) do
      session = A2UIPhoenix.Session.new([A2UICore.Catalog.Basic.catalog("v1.0")])
      {:ok, A2UIPhoenix.Live.init(socket, session, on_send: &send_to_agent/2)}
    end

    def handle_info({:agent, payload}, socket) do
      {_result, socket} = A2UIPhoenix.Live.handle_message(socket, payload)
      {:noreply, socket}
    end

and render each surface with `A2UIPhoenix.Surface`:

```heex
<.live_component
  :for={surface <- A2UIPhoenix.Session.surfaces(@a2ui)}
  module={A2UIPhoenix.Surface}
  id={"surface-" <> surface.id}
  session={@a2ui}
  surface_id={surface.id}
/>
```

`init/3` assigns the session and attaches a `handle_info` hook that
applies the writes and actions the surfaces report, so the host does not
handle those messages itself.

Effects are delivered as they happen:

  * `{:send, message}` goes to the `:on_send` callback — the host's
    transport to the agent;
  * `{:open_url, url}` is pushed to the browser as the `"a2ui:open_url"`
    event (`priv/static/a2ui_phoenix.js` opens it in a new tab);
  * `{:agent_call_sent, call_id, timeout_ms}` starts the call's timer,
    which rejects the call with `TIMEOUT` if the agent has not answered
    when it fires (`A2UIPhoenix.Session.timeout_agent_call/2`), and also
    goes to the `:on_effect` callback;
  * every other effect goes to the `:on_effect` callback.

The reply to an embedded MCP App's request is pushed as the
`"a2ui:mcp_app:reply"` event, which the `A2UIMcpApp` hook relays to the
app.

# `callback`
*since 0.1.0* 

```elixir
@type callback() :: (term(), Phoenix.LiveView.Socket.t() -&gt;
                 Phoenix.LiveView.Socket.t())
```

# `handle_message`
*since 0.1.0* 

```elixir
@spec handle_message(Phoenix.LiveView.Socket.t(), term(), keyword()) ::
  {:ok | {:error, A2UICore.Error.t()}, Phoenix.LiveView.Socket.t()}
```

Applies an agent payload to the session (`A2UIPhoenix.Session.handle_message/3`)
and delivers the effects. Returns `:ok` or `{:error, error}` with the
updated socket: a failed message may still have changed some surfaces,
and its `error` report has been sent.

# `init`
*since 0.1.0* 

```elixir
@spec init(Phoenix.LiveView.Socket.t(), A2UIPhoenix.Session.t(), keyword()) ::
  Phoenix.LiveView.Socket.t()
```

Assigns `session` and attaches the hook.

Options:

  * `:assign` — the assign holding the session (`:a2ui`);
  * `:on_send` — `(message, socket -> socket)`, called for each
    renderer→agent message;
  * `:on_effect` — `(effect, socket -> socket)`, called for the other
    session effects.

# `session`
*since 0.1.0* 

```elixir
@spec session(Phoenix.LiveView.Socket.t()) :: A2UIPhoenix.Session.t()
```

The session `init/3` assigned.

---

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