Files
nanobot/nanobot/webui/gateway_services.py
T

142 lines
5.4 KiB
Python

"""Composition helpers for the embedded WebUI gateway."""
from __future__ import annotations
from collections.abc import Awaitable, Mapping
from dataclasses import dataclass
from pathlib import Path
from typing import TYPE_CHECKING, Any, Callable
from loguru import logger as default_logger
from nanobot.config.loader import get_config_path
from nanobot.webui.gateway_tokens import GatewayTokenStore
from nanobot.webui.ingress_policy import DEFAULT_WEBUI_INGRESS_POLICY, WebUIIngressPolicy
from nanobot.webui.media_gateway import WebUIMediaGateway
from nanobot.webui.settings_services import WebUISettingsServices
from nanobot.webui.temporary_chats import WebUITemporaryChats
from nanobot.webui.transcript import WebUITranscriptRecorder
from nanobot.webui.workspaces import WebUIWorkspaceController
from nanobot.webui.ws_http import GatewayHTTPHandler
if TYPE_CHECKING:
from nanobot.bus.queue import MessageBus
from nanobot.channels.websocket.runtime import WebSocketConfig
from nanobot.cron.service import CronService
from nanobot.session.manager import SessionManager
from nanobot.triggers.local_store import LocalTriggerStore
@dataclass(frozen=True)
class GatewayServices:
"""Explicit dependencies shared by WebSocket transport and HTTP routes."""
http: GatewayHTTPHandler
settings: WebUISettingsServices
tokens: GatewayTokenStore
media: WebUIMediaGateway
ingress: WebUIIngressPolicy
transcripts: WebUITranscriptRecorder
workspaces: WebUIWorkspaceController
temporary_chats: WebUITemporaryChats
session_manager: SessionManager | None
cron_service: CronService | None
local_trigger_store: LocalTriggerStore | None
cron_pending_job_ids: Callable[[str], set[str]] | None
local_trigger_pending_ids: Callable[[str], set[str]] | None
def build_gateway_services(
*,
config: WebSocketConfig,
bus: MessageBus,
session_manager: SessionManager | None,
static_dist_path: Path | None,
workspace_path: Path,
default_restrict_to_workspace: bool,
config_path: Path | None = None,
runtime_model_name: Callable[[], str | None] | None,
runtime_surface: str,
runtime_capabilities_overrides: dict[str, Any] | None,
disabled_skills: set[str] | None = None,
cron_service: CronService | None = None,
local_trigger_store: LocalTriggerStore | None = None,
cron_pending_job_ids: Callable[[str], set[str]] | None = None,
local_trigger_pending_ids: Callable[[str], set[str]] | None = None,
channel_feature_action: Callable[..., Any] | None = None,
channel_runtime_status: Callable[[], dict[str, Any]] | None = None,
mcp_runtime_status: Callable[[], Mapping[str, str]] | None = None,
mcp_reload: Callable[[], Awaitable[dict[str, Any]]] | None = None,
skill_state_action: Callable[[set[str]], None] | None = None,
logger: Any = default_logger,
) -> GatewayServices:
settings = WebUISettingsServices.create(config_path or get_config_path())
tokens = GatewayTokenStore()
ingress = DEFAULT_WEBUI_INGRESS_POLICY
minimum_frame_bytes = ingress.minimum_full_policy_frame_bytes()
if config.max_message_bytes < minimum_frame_bytes:
logger.warning(
"WebSocket maxMessageBytes={} is below the WebUI ingress policy capacity={}; "
"policy-valid messages may still hit the transport frame guard",
config.max_message_bytes,
minimum_frame_bytes,
)
media = WebUIMediaGateway(
workspace_path=workspace_path,
logger=logger,
attachment_limits=ingress.attachments,
)
transcripts = WebUITranscriptRecorder(log=logger)
workspaces = WebUIWorkspaceController(
session_manager=session_manager,
default_workspace=workspace_path,
default_restrict_to_workspace=default_restrict_to_workspace,
)
temporary_chats = WebUITemporaryChats(
bus=bus,
session_manager=session_manager,
workspaces=workspaces,
logger=logger,
)
http = GatewayHTTPHandler(
config=config,
session_manager=session_manager,
static_dist_path=static_dist_path,
runtime_model_name=runtime_model_name,
runtime_surface=runtime_surface,
runtime_capabilities_overrides=runtime_capabilities_overrides,
bus=bus,
tokens=tokens,
media=media,
ingress=ingress,
workspaces=workspaces,
settings=settings,
skills_workspace_path=workspace_path,
disabled_skills=disabled_skills,
cron_service=cron_service,
local_trigger_store=local_trigger_store,
cron_pending_job_ids=cron_pending_job_ids,
local_trigger_pending_ids=local_trigger_pending_ids,
channel_feature_action=channel_feature_action,
channel_runtime_status=channel_runtime_status,
mcp_runtime_status=mcp_runtime_status,
mcp_reload=mcp_reload,
skill_state_action=skill_state_action,
log=logger,
)
return GatewayServices(
http=http,
settings=settings,
tokens=tokens,
media=media,
ingress=ingress,
transcripts=transcripts,
workspaces=workspaces,
temporary_chats=temporary_chats,
session_manager=session_manager,
cron_service=cron_service,
local_trigger_store=local_trigger_store,
cron_pending_job_ids=cron_pending_job_ids,
local_trigger_pending_ids=local_trigger_pending_ids,
)