Packages
Phoenix LiveView renderer for A2UI surfaces: the basic catalog as function components, two-way bindings, actions, and A2UI messages over SSE.
Current section
Files
Jump to
Current section
Files
a2ui_phoenix
README.md
README.md
# A2UIPhoenix
A Phoenix LiveView renderer for [A2UI](https://a2ui.org) surfaces, built on
`a2ui_core`. It renders the basic catalog (protocols v0.9, v0.9.1 and v1.0)
as function components, keeps two-way bindings in the surface's data model,
and turns user actions into renderer→agent messages.
## Installation
```elixir
def deps do
[
{:a2ui_phoenix, "~> 0.1.0"}
]
end
```
## Usage
```elixir
defmodule MyAppWeb.AgentLive do
use MyAppWeb, :live_view
alias A2UIPhoenix.{Live, Session}
def mount(_params, _session, socket) do
# Check every component against its catalog; relaxed validation still
# accepts a surface whose components arrive over several messages.
validation = A2UICore.Validation.Config.relaxed()
session = Session.new([A2UICore.Catalog.Basic.catalog("v1.0")], validation: validation)
{:ok, Live.init(socket, session, on_send: &send_to_agent/2)}
end
# Messages from the agent, however they arrive (SSE, A2A, a process).
def handle_info({:agent, payload}, socket) do
{_result, socket} = Live.handle_message(socket, payload)
{:noreply, socket}
end
def render(assigns) do
~H"""
<.live_component
:for={surface <- Session.surfaces(@a2ui)}
module={A2UIPhoenix.Surface}
id={"surface-" <> surface.id}
session={@a2ui}
surface_id={surface.id}
/>
"""
end
# Messages for the agent (`action`, `error`, `callAgentFunction`,
# `rendererFunctionResponse`), here broadcast to the process that talks to it.
defp send_to_agent(message, socket) do
Phoenix.PubSub.broadcast(MyApp.PubSub, "a2ui:renderer", {:renderer, self(), message})
socket
end
end
```
Add `priv/static/a2ui_phoenix.js` to the page's scripts, so that `openUrl` actions
open their URL, and `priv/static/a2ui_phoenix.css`, the components' design
system: light and dark, themed by `--a2ui-*` custom properties (or replaced
by your own styles for the `a2ui-*` classes). The script also holds the hook of the MCP
catalog's `McpApp` component (`hooks: {...window.A2UIPhoenix.hooks}`), whose
sandbox proxy page, `priv/static/a2ui_mcp_sandbox.html`, the endpoint serves.
[Rendering surfaces](guides/rendering_surfaces.md) shows how to load them,
and covers theming, agent functions and the MCP catalog.
A catalog of your own brings its components as a map:
```heex
<.live_component module={A2UIPhoenix.Surface} components={%{"Chart" => &chart/1}} ... />
```
Each component receives `@ctx`, `@node`, `@props` (bindings resolved),
`@a11y` and `@attrs`; see `A2UIPhoenix.Components`.
## Streaming to other renderers
`A2UIPhoenix.Plug.SSE` streams A2UI messages to a renderer outside LiveView,
such as a web renderer in the browser, as server-sent events, one message per
event:
```elixir
# In a controller:
def events(conn, params), do: A2UIPhoenix.Plug.SSE.stream(conn, MyAgent.messages(params))
# Or mounted in a router; for each request the plug calls MyAgent.messages(conn):
forward "/a2ui/events", A2UIPhoenix.Plug.SSE, source: {MyAgent, :messages, []}
```
## License
Apache-2.0