跳转至

API reference

Generated from the apogee-ai-ui source with mkdocstrings. Every symbol below is exported from apogee_ai_ui, so it is part of the supported public surface.

Application · DTOs

BenchDTO dataclass

Python
BenchDTO(frames: int = 200)

frames class-attribute instance-attribute

Python
frames: int = 200

RenderDTO dataclass

Python
RenderDTO(component: object, renderer: str = 'plain')

component instance-attribute

Python
component: object

renderer class-attribute instance-attribute

Python
renderer: str = 'plain'

StreamDTO dataclass

Python
StreamDTO(component_id: str = 'main')

component_id class-attribute instance-attribute

Python
component_id: str = 'main'

Application · Use cases

BenchRenderUseCase

Renders a moderately complex tree N times and reports throughput.

execute async

Python
execute(frames: int) -> dict[str, float]
Source code in apogee_ai_ui/application/use_cases/bench_render_use_case.py
Python
async def execute(self, frames: int) -> dict[str, float]:
    if frames <= 0:
        raise ValueError("frames must be positive")
    tree = Container(children=[
        Heading(text="bench"),
        Markdown(source="**bold** demo " * 5),
        List(items=tuple(f"item-{i}" for i in range(20))),
        Table(
            headers=("a", "b", "c"),
            rows=tuple(("x", str(i), "y") for i in range(20)),
        ),
    ])
    renderer = PlainTextRenderer()
    start = time.perf_counter()
    for _ in range(frames):
        renderer.render(tree)
    elapsed = (time.perf_counter() - start) * 1000.0
    return {
        "frames": float(frames),
        "elapsed_ms": elapsed,
        "frames_per_second": (frames / elapsed * 1000.0) if elapsed > 0 else 0.0,
    }

BuildDemoUseCase

Constructs a representative tree using all major component kinds.

execute async

Python
execute() -> UiComponent
Source code in apogee_ai_ui/application/use_cases/build_demo_use_case.py
Python
async def execute(self) -> UiComponent:
    return Container(children=[
        Heading(text="apogee-ai-ui — demo", level=1),
        Markdown(source="UI **declarativa** para AI agents."),
        Panel(title="Resultado", children=[
            Card(title="Score", body="0.87"),
            ProgressBar(value=0.87, label="confidence"),
        ]),
        List(items=["Text", "Heading", "Markdown", "Table", "Code"]),
        Table(
            headers=("Engine", "Status"),
            rows=(("echo", "ok"), ("vllm", "lazy")),
        ),
        Code(source='print("hi")', language="python"),
        ChatMessage(role="assistant", content="Olá! Posso ajudar?"),
        Spinner(label="Pensando..."),
    ])

ListComponentsUseCase

execute async

Python
execute() -> list[str]
Source code in apogee_ai_ui/application/use_cases/list_components_use_case.py
Python
async def execute(self) -> list[str]:
    return [k.value for k in ComponentKind]

RenderUseCase

execute async

Python
execute(component: UiComponent, renderer: str = 'plain') -> str
Source code in apogee_ai_ui/application/use_cases/render_use_case.py
Python
async def execute(self, component: UiComponent, renderer: str = "plain") -> str:
    if renderer not in _RENDERERS:
        raise RendererError(f"unknown renderer: {renderer!r}")
    return _RENDERERS[renderer]().render(component)

StreamTokensUseCase

Consumes an async string source and yields UiUpdate appends.

execute async

Python
execute(source: AsyncIterator[str], component_id: str = 'main') -> AsyncIterator[UiUpdate]
Source code in apogee_ai_ui/application/use_cases/stream_tokens_use_case.py
Python
async def execute(
    self, source: AsyncIterator[str], component_id: str = "main"
) -> AsyncIterator[UiUpdate]:
    async for update in TokenStream(source, component_id=component_id).updates():
        yield update

Domain

UiComponent dataclass

Python
UiComponent(kind: ComponentKind, id: str = (lambda: f'c-{hex[:8]}')(), text: str = '', props: dict[str, str] = dict(), children: tuple['UiComponent', ...] = ())

Generic component node. Concrete components are factories that fill kind, text, props, children accordingly. Frozen → immutable tree; updates produce new components.

kind instance-attribute

Python
kind: ComponentKind

id class-attribute instance-attribute

Python
id: str = field(default_factory=lambda: f'c-{hex[:8]}')

text class-attribute instance-attribute

Python
text: str = ''

props class-attribute instance-attribute

Python
props: dict[str, str] = field(default_factory=dict)

children class-attribute instance-attribute

Python
children: tuple['UiComponent', ...] = ()

with_props

Python
with_props(**extra: str) -> 'UiComponent'
Source code in apogee_ai_ui/domain/entities/ui_component.py
Python
def with_props(self, **extra: str) -> "UiComponent":
    merged = {**self.props, **{k: str(v) for k, v in extra.items()}}
    return UiComponent(
        kind=self.kind, id=self.id, text=self.text,
        props=merged, children=self.children,
    )

UiEvent dataclass

Python
UiEvent(kind: UiEventKind, component_id: str | None = None, payload: dict[str, str] = dict(), sequence: int = 0)

kind instance-attribute

Python
kind: UiEventKind

component_id class-attribute instance-attribute

Python
component_id: str | None = None

payload class-attribute instance-attribute

Python
payload: dict[str, str] = field(default_factory=dict)

sequence class-attribute instance-attribute

Python
sequence: int = 0

UiSession dataclass

Python
UiSession(id: str, events: list[UiEvent] = list(), state: dict[str, str] = dict())

id instance-attribute

Python
id: str

events class-attribute instance-attribute

Python
events: list[UiEvent] = field(default_factory=list)

state class-attribute instance-attribute

Python
state: dict[str, str] = field(default_factory=dict)

append

Python
append(event: UiEvent) -> None
Source code in apogee_ai_ui/domain/entities/ui_session.py
Python
def append(self, event: UiEvent) -> None:
    self.events.append(event)

UiUpdate dataclass

Python
UiUpdate(component_id: str, delta_text: str = '', progress: float | None = None, done: bool = False)

component_id instance-attribute

Python
component_id: str

delta_text class-attribute instance-attribute

Python
delta_text: str = ''

progress class-attribute instance-attribute

Python
progress: float | None = None

done class-attribute instance-attribute

Python
done: bool = False

Domain · Enums

ComponentKind

Bases: str, Enum

TEXT class-attribute instance-attribute

Python
TEXT = 'text'

HEADING class-attribute instance-attribute

Python
HEADING = 'heading'

MARKDOWN class-attribute instance-attribute

Python
MARKDOWN = 'markdown'

LIST class-attribute instance-attribute

Python
LIST = 'list'

TABLE class-attribute instance-attribute

Python
TABLE = 'table'

CODE class-attribute instance-attribute

Python
CODE = 'code'

PROGRESS class-attribute instance-attribute

Python
PROGRESS = 'progress'

CARD class-attribute instance-attribute

Python
CARD = 'card'

CONTAINER class-attribute instance-attribute

Python
CONTAINER = 'container'

PANEL class-attribute instance-attribute

Python
PANEL = 'panel'

SPINNER class-attribute instance-attribute

Python
SPINNER = 'spinner'

CHAT_MESSAGE class-attribute instance-attribute

Python
CHAT_MESSAGE = 'chat_message'

RendererKind

Bases: str, Enum

PLAIN class-attribute instance-attribute

Python
PLAIN = 'plain'

TERMINAL class-attribute instance-attribute

Python
TERMINAL = 'terminal'

HTML class-attribute instance-attribute

Python
HTML = 'html'

JSON class-attribute instance-attribute

Python
JSON = 'json'

UiEventKind

Bases: str, Enum

APPEND class-attribute instance-attribute

Python
APPEND = 'append'

REPLACE class-attribute instance-attribute

Python
REPLACE = 'replace'

REMOVE class-attribute instance-attribute

Python
REMOVE = 'remove'

UPDATE class-attribute instance-attribute

Python
UPDATE = 'update'

PROGRESS class-attribute instance-attribute

Python
PROGRESS = 'progress'

DONE class-attribute instance-attribute

Python
DONE = 'done'

Domain · Exceptions

RendererError

Bases: UiError

SessionNotFoundException

Python
SessionNotFoundException(session_id: str)

Bases: UiError

Source code in apogee_ai_ui/domain/exceptions/ui_exceptions.py
Python
def __init__(self, session_id: str) -> None:
    super().__init__(f"Session not found: {session_id!r}")
    self.session_id = session_id

session_id instance-attribute

Python
session_id = session_id

UiError

Bases: Exception

Base for apogee-ai-ui errors.

Domain · Protocols (ports)

IRenderer

Bases: Protocol

name instance-attribute

Python
name: str

render

Python
render(component: UiComponent) -> str
Source code in apogee_ai_ui/domain/services/i_renderer.py
Python
def render(self, component: UiComponent) -> str: ...

ISessionStore

Bases: Protocol

create

Python
create(session_id: str) -> UiSession
Source code in apogee_ai_ui/domain/services/i_session_store.py
Python
def create(self, session_id: str) -> UiSession: ...

get

Python
get(session_id: str) -> UiSession
Source code in apogee_ai_ui/domain/services/i_session_store.py
Python
def get(self, session_id: str) -> UiSession: ...

drop

Python
drop(session_id: str) -> None
Source code in apogee_ai_ui/domain/services/i_session_store.py
Python
def drop(self, session_id: str) -> None: ...

IStream

Bases: Protocol

updates

Python
updates() -> AsyncIterator[UiUpdate]
Source code in apogee_ai_ui/domain/services/i_stream.py
Python
def updates(self) -> AsyncIterator[UiUpdate]: ...

Infrastructure

Card

Python
Card(title: str, body: str, *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Card(title: str, body: str, *, id: str | None = None) -> UiComponent:
    return UiComponent(
        kind=ComponentKind.CARD, text=title,
        props={"body": body},
        **({"id": id} if id else {}),
    )

ChatMessage

Python
ChatMessage(role: str, content: str, *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def ChatMessage(role: str, content: str, *, id: str | None = None) -> UiComponent:
    if role not in {"user", "assistant", "system", "tool"}:
        raise ValueError(f"unknown chat role: {role!r}")
    return UiComponent(
        kind=ComponentKind.CHAT_MESSAGE, text=content,
        props={"role": role},
        **({"id": id} if id else {}),
    )

Code

Python
Code(source: str, *, language: str = '', id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Code(source: str, *, language: str = "", id: str | None = None) -> UiComponent:
    return UiComponent(
        kind=ComponentKind.CODE, text=source,
        props={"language": language},
        **({"id": id} if id else {}),
    )

Container

Python
Container(children: Iterable[UiComponent], *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Container(children: Iterable[UiComponent], *, id: str | None = None) -> UiComponent:
    return UiComponent(
        kind=ComponentKind.CONTAINER,
        children=tuple(children),
        **({"id": id} if id else {}),
    )

Heading

Python
Heading(text: str, *, level: int = 1, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Heading(text: str, *, level: int = 1, id: str | None = None) -> UiComponent:
    if not 1 <= level <= 6:
        raise ValueError("level must be in [1, 6]")
    return UiComponent(
        kind=ComponentKind.HEADING, text=text,
        props={"level": str(level)},
        **({"id": id} if id else {}),
    )

HtmlRenderer

Pure-stdlib HTML renderer. Output is escaped for safety.

name class-attribute instance-attribute

Python
name = 'html'

render

Python
render(component: UiComponent) -> str
Source code in apogee_ai_ui/infrastructure/renderers/html_renderer.py
Python
def render(self, component: UiComponent) -> str:
    return self._render(component)

InMemorySessionStore

Python
InMemorySessionStore()
Source code in apogee_ai_ui/infrastructure/sessions/in_memory_session_store.py
Python
def __init__(self) -> None:
    self._sessions: dict[str, UiSession] = {}

name class-attribute instance-attribute

Python
name = 'in_memory'

create

Python
create(session_id: str) -> UiSession
Source code in apogee_ai_ui/infrastructure/sessions/in_memory_session_store.py
Python
def create(self, session_id: str) -> UiSession:
    if session_id in self._sessions:
        return self._sessions[session_id]
    session = UiSession(id=session_id)
    self._sessions[session_id] = session
    return session

get

Python
get(session_id: str) -> UiSession
Source code in apogee_ai_ui/infrastructure/sessions/in_memory_session_store.py
Python
def get(self, session_id: str) -> UiSession:
    if session_id not in self._sessions:
        raise SessionNotFoundException(session_id)
    return self._sessions[session_id]

drop

Python
drop(session_id: str) -> None
Source code in apogee_ai_ui/infrastructure/sessions/in_memory_session_store.py
Python
def drop(self, session_id: str) -> None:
    self._sessions.pop(session_id, None)

count

Python
count() -> int
Source code in apogee_ai_ui/infrastructure/sessions/in_memory_session_store.py
Python
def count(self) -> int:
    return len(self._sessions)

JsonRenderer

Serialises the component tree as JSON for transport / debugging.

name class-attribute instance-attribute

Python
name = 'json'

render

Python
render(component: UiComponent) -> str
Source code in apogee_ai_ui/infrastructure/renderers/json_renderer.py
Python
def render(self, component: UiComponent) -> str:
    return json.dumps(self._serialise(component), indent=2)

List

Python
List(items: Iterable[str], *, ordered: bool = False, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def List(items: Iterable[str], *, ordered: bool = False, id: str | None = None) -> UiComponent:
    children = tuple(UiComponent(kind=ComponentKind.TEXT, text=item) for item in items)
    return UiComponent(
        kind=ComponentKind.LIST,
        props={"ordered": str(ordered).lower()},
        children=children,
        **({"id": id} if id else {}),
    )

Markdown

Python
Markdown(source: str, *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Markdown(source: str, *, id: str | None = None) -> UiComponent:
    return UiComponent(
        kind=ComponentKind.MARKDOWN, text=source,
        **({"id": id} if id else {}),
    )

Panel

Python
Panel(title: str, children: Iterable[UiComponent], *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Panel(title: str, children: Iterable[UiComponent], *, id: str | None = None) -> UiComponent:
    return UiComponent(
        kind=ComponentKind.PANEL, text=title,
        children=tuple(children),
        **({"id": id} if id else {}),
    )

PlainTextRenderer

name class-attribute instance-attribute

Python
name = 'plain'

render

Python
render(component: UiComponent) -> str
Source code in apogee_ai_ui/infrastructure/renderers/plain_text_renderer.py
Python
def render(self, component: UiComponent) -> str:
    return self._render(component, depth=0)

ProgressBar

Python
ProgressBar(value: float, total: float = 1.0, *, label: str = '', id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def ProgressBar(value: float, total: float = 1.0, *, label: str = "", id: str | None = None) -> UiComponent:
    if total <= 0:
        raise ValueError("total must be positive")
    if not 0.0 <= value <= total:
        raise ValueError(f"value must be in [0, {total}]")
    return UiComponent(
        kind=ComponentKind.PROGRESS, text=label,
        props={"value": str(value), "total": str(total)},
        **({"id": id} if id else {}),
    )

ProgressStream

Python
ProgressStream(steps: int, component_id: str = 'progress')

Emits UiUpdate with progress 0..1 over steps increments.

Source code in apogee_ai_ui/infrastructure/streams/progress_stream.py
Python
def __init__(self, steps: int, component_id: str = "progress") -> None:
    if steps <= 0:
        raise ValueError("steps must be positive")
    self._steps = steps
    self._component_id = component_id

name class-attribute instance-attribute

Python
name = 'progress'

updates async

Python
updates() -> AsyncIterator[UiUpdate]
Source code in apogee_ai_ui/infrastructure/streams/progress_stream.py
Python
async def updates(self) -> AsyncIterator[UiUpdate]:
    for i in range(1, self._steps + 1):
        yield UiUpdate(
            component_id=self._component_id,
            progress=i / self._steps,
            done=i == self._steps,
        )

Spinner

Python
Spinner(label: str = '', *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Spinner(label: str = "", *, id: str | None = None) -> UiComponent:
    return UiComponent(
        kind=ComponentKind.SPINNER, text=label,
        **({"id": id} if id else {}),
    )

Table

Python
Table(headers: tuple[str, ...], rows: tuple[tuple[str, ...], ...], *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Table(headers: tuple[str, ...], rows: tuple[tuple[str, ...], ...], *, id: str | None = None) -> UiComponent:
    if not headers:
        raise ValueError("headers cannot be empty")
    if any(len(r) != len(headers) for r in rows):
        raise ValueError("all rows must match headers length")
    children = (
        UiComponent(
            kind=ComponentKind.TEXT,
            text="\t".join(headers),
            props={"role": "header"},
        ),
        *(
            UiComponent(
                kind=ComponentKind.TEXT,
                text="\t".join(row),
                props={"role": "row"},
            )
            for row in rows
        ),
    )
    return UiComponent(
        kind=ComponentKind.TABLE,
        children=children,
        **({"id": id} if id else {}),
    )

TerminalRenderer

Adds ANSI styling on top of the plain layout.

name class-attribute instance-attribute

Python
name = 'terminal'

render

Python
render(component: UiComponent) -> str
Source code in apogee_ai_ui/infrastructure/renderers/terminal_renderer.py
Python
def render(self, component: UiComponent) -> str:
    return self._render(component)

Text

Python
Text(text: str, *, id: str | None = None) -> UiComponent
Source code in apogee_ai_ui/infrastructure/components/factories.py
Python
def Text(text: str, *, id: str | None = None) -> UiComponent:
    return UiComponent(kind=ComponentKind.TEXT, text=text, **({"id": id} if id else {}))

TokenStream

Python
TokenStream(source: AsyncIterator[str], component_id: str = 'main')

Wraps an async iterator of strings into a stream of UiUpdate appends.

Source code in apogee_ai_ui/infrastructure/streams/token_stream.py
Python
def __init__(self, source: AsyncIterator[str], component_id: str = "main") -> None:
    self._source = source
    self._component_id = component_id

name class-attribute instance-attribute

Python
name = 'token'

updates async

Python
updates() -> AsyncIterator[UiUpdate]
Source code in apogee_ai_ui/infrastructure/streams/token_stream.py
Python
async def updates(self) -> AsyncIterator[UiUpdate]:
    async for chunk in self._source:
        yield UiUpdate(component_id=self._component_id, delta_text=chunk)
    yield UiUpdate(component_id=self._component_id, done=True)