Files
webber/webber-api/src/shared/config.py
T
jpmschweitzerandClaude Opus 4.5 3b58fa4f8b
Build and Push API / release (push) Successful in 3s
Build and Push API / build (push) Successful in 2m27s
refactor: reorganize into monorepo with separate subprojects
Structure webber into three independent subprojects:
- webber-api/: FastAPI backend server with all agent code
- webber-cli/: Standalone CLI client (renamed from cli/ to webber_cli/)
- webber-sandbox/: Test project for functional testing

Key changes:
- Each subproject has its own .venv (Python 3.12+)
- Added sandbox.sh for managing test project templates
- Created sandbox-templates/ with calculator-cli and empty starter
- Updated CI/CD for prefixed tags (api/v*, cli/v*)
- Added comprehensive AGENTS.md with operational instructions
- Added gitignore filtering to glob and grep tools
- Created pyproject.toml for each subproject

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-10 10:37:47 +01:00

100 lines
2.8 KiB
Python

"""
Application configuration via Pydantic Settings.
All settings loaded from environment variables or .env file.
Project metadata (name, version, description) sourced from pyproject.toml.
"""
import tomllib
from dataclasses import dataclass
from functools import lru_cache
from pathlib import Path
from pydantic_settings import BaseSettings, SettingsConfigDict
@dataclass(frozen=True)
class ProjectMeta:
"""Project metadata from pyproject.toml (single source of truth)."""
name: str
version: str
description: str
def _load_project_meta() -> ProjectMeta:
"""Load project metadata from pyproject.toml."""
pyproject_path = Path(__file__).parent.parent.parent / "pyproject.toml"
try:
with open(pyproject_path, "rb") as f:
data = tomllib.load(f)
project = data.get("project", {})
return ProjectMeta(
name=str(project.get("name", "webber")).title(),
version=str(project.get("version", "0.0.0")),
description=str(project.get("description", "")),
)
except FileNotFoundError:
return ProjectMeta(name="Webber", version="0.0.0", description="")
PROJECT = _load_project_meta()
__version__ = PROJECT.version
class Settings(BaseSettings):
"""Application settings loaded from environment."""
# Application (from pyproject.toml)
app_name: str = PROJECT.name
app_version: str = PROJECT.version
app_description: str = PROJECT.description
debug: bool = False
# Server
host: str = "0.0.0.0"
port: int = 8086
# Logging
log_level: str = "INFO"
# CORS
cors_origins: list[str] = ["http://localhost:3000", "http://localhost:8080"]
cors_credentials: bool = True
cors_methods: list[str] = ["*"]
cors_headers: list[str] = ["*"]
# LLM - Ollama (always hot in VRAM on tower-of-joy)
ollama_url: str = "http://192.168.86.149:11434"
ollama_agent_model: str = "mistral-nemo-large:latest"
ollama_embed_model: str = "nomic-embed-text:latest"
# Auth - Tatlock integration
tatlock_api_url: str | None = "http://192.168.86.149:8000"
internal_api_key: str | None = None
# Tool execution
tool_timeout_seconds: int = 120
sandbox_enabled: bool = True
allowed_paths: list[str] | None = None
# Sessions
session_ttl_hours: int = 24
max_context_tokens: int = 128000
model_config = SettingsConfigDict(
env_file=".env",
case_sensitive=False,
extra="ignore",
env_parse_none_str="", # Treat empty string as None
)
@property
def effective_allowed_paths(self) -> list[str]:
"""Return allowed_paths or empty list if None."""
return self.allowed_paths or []
@lru_cache
def get_settings() -> Settings:
"""Cached settings singleton."""
return Settings()