"""Application settings loaded from TOML with env-var overrides.""" from __future__ import annotations import os from pathlib import Path from pydantic import BaseModel, Field from pydantic_settings import ( BaseSettings, PydanticBaseSettingsSource, SettingsConfigDict, TomlConfigSettingsSource, ) class MeshCoreCfg(BaseModel): serial_port: str baud_rate: int = 115200 class LLMCfg(BaseModel): base_url: str api_key: str = "not-needed" model: str system_prompt: str = ( "You are a concise assistant on a low-bandwidth mesh radio. " "Replies must be brief — under 180 bytes." ) temperature: float = 0.7 request_timeout_seconds: float = 60.0 class StorageCfg(BaseModel): sqlite_path: Path = Path("data/meshbot.db") class MessageCfg(BaseModel): max_bytes: int = Field(default=184, gt=0) def _toml_path() -> Path: return Path(os.environ.get("MESHBOT_CONFIG", "config.toml")) class Settings(BaseSettings): meshcore: MeshCoreCfg llm: LLMCfg storage: StorageCfg = StorageCfg() message: MessageCfg = MessageCfg() model_config = SettingsConfigDict( env_prefix="MESHBOT_", env_nested_delimiter="__", toml_file=_toml_path(), extra="ignore", ) @classmethod def settings_customise_sources( cls, settings_cls: type[BaseSettings], init_settings: PydanticBaseSettingsSource, env_settings: PydanticBaseSettingsSource, dotenv_settings: PydanticBaseSettingsSource, file_secret_settings: PydanticBaseSettingsSource, ) -> tuple[PydanticBaseSettingsSource, ...]: # Order = priority (highest first): init args > env > TOML > secrets. return ( init_settings, env_settings, TomlConfigSettingsSource(settings_cls), file_secret_settings, )