Source code for klea_utils.ui.web.nicegui.components.context

#!/usr/bin/env python3
"""
Shared page context for Klea NiceGUI components.

A :class:`PageContext` carries everything the reusable components need
to coordinate without being assembled into a single closure: the page
configuration, the mutable runtime state (active chat, expand state,
streaming flag), the NiceGUI element references, and the
cross-component callbacks.  Components write into the context at
attach time; handlers read it at event time, after the whole page has
been assembled.

File: klea_utils/ui/web/nicegui/components/context.py

Copyright 2026 Ankur Sinha
Author: Ankur Sinha <sanjay DOT ankur AT gmail DOT com>
"""

from __future__ import annotations

from collections.abc import Callable
from dataclasses import dataclass, field
from typing import Any

DEFAULT_FOOTER = 'Powered by <a href="https://github.com/neuroml/klea">Klea</a>'


def _noop() -> None:
    """No-op default for callbacks that are not yet/never registered."""


def _noop_arg(_: str) -> None:
    """No-op default for one-argument callbacks (e.g. chat switching)."""


[docs] @dataclass class PageContext: """Shared mutable state and element/callback registry for a Klea page. Components (``components/*.py``) attach into this object: they read the configuration, keep their mutable state here, and register the element references and cross-component callbacks they need. The page assembly creates one context, attaches all components, then lets handlers resolve references at event time. :param server_url: Base URL of the backend API server. :param user_id: Opaque persistent user identifier. :param title: Bold application title in the header bar. :param subtitle: Optional smaller text shown next to *title*. :param disclaimer: Optional text shown below the chat input. :param footer_text: HTML content for the footer bar. :param chat_id: Active chat conversation identifier. """ server_url: str user_id: str title: str = "Klea" subtitle: str = "" disclaimer: str = "" footer_text: str = DEFAULT_FOOTER chat_id: str = "" # Mutable runtime state expanded: set[int] = field(default_factory=set) is_streaming: bool = False mini_state: bool = True # Extra request fields merged into the ``/query/stream`` POST body # (e.g. an app-specific operating ``mode`` request, ADR-0030). The # app UI writes it; the shared stream driver forwards it. query_extra: dict[str, Any] = field(default_factory=dict) # Element references (filled by components at attach time) dark: Any = None left_drawer: Any = None toggle_icon: Any = None center_panels: Any = None chat_area: Any = None scroll_area: Any = None stream_container: Any = None text: Any = None loading_row: Any = None # Cross-component callbacks (registered by components at attach time # and invoked by handlers after the page is fully assembled) render_chat_area: Callable[[], None] = field(default=_noop) scroll_chat_bottom: Callable[[], None] = field(default=_noop) refresh_chat_list: Callable[..., Any] = field(default=_noop) refresh_status_pane: Callable[..., Any] = field(default=_noop) refresh_inspector: Callable[..., Any] = field(default=_noop) reset_center_tab: Callable[[], None] = field(default=_noop) fetch_model_info: Callable[[], Any] | None = None model_config_dialog: Callable[[], Any] | None = None # App-defined content rendered inside the (refreshable) status pane, # e.g. an operating-mode selector/badge (ADR-0030). status_extra: Callable[[], Any] | None = None switch_chat: Callable[[str], None] = field(default=_noop_arg)