style: apply ruff's automatic fixes and formatter
Mechanical only, and separated from the judgment calls that follow so the reviewable changes are not buried in a 98-file whitespace diff. 227 automatic fixes: 60 blank lines carrying whitespace, 60 unsorted import blocks, 34 Optional[X] to X | None, 28 unused imports, 16 deprecated typing imports, 12 datetime.timezone.utc to datetime.UTC, and assorted smaller modernisations. Then `ruff format` over src and tests: 98 files reformatted, 35 already conforming. No file among the unused-import findings defines __all__ or is an __init__.py, so nothing here removes a re-export. `make test`: 658 passed, unchanged from HEAD. Two things observed while verifying, neither addressed here: `pytest tests/` cannot collect — tests/e2e/test_orchestration_e2e.py uses an `e2e` marker that is not registered, and the config is strict about markers. This fails identically at HEAD, so it predates this change; `make test` passes because it ignores tests/e2e, tests/integration and tests/contracts. test_tatlock_tool_call_logging_calculator is flaky. It failed once in a full run with these changes and passed on the next, passes in isolation with them, and fails in isolation at HEAD. It is order- or timing-dependent, not a regression from this commit — established by running the full suite both ways rather than by reasoning about which change could have caused it. Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
+34
-86
@@ -2,6 +2,7 @@
|
||||
Global application configuration.
|
||||
Following best practice of splitting config across domains.
|
||||
"""
|
||||
|
||||
from enum import Enum
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
@@ -42,6 +43,7 @@ def _get_version_from_pyproject() -> str:
|
||||
|
||||
class Environment(str, Enum):
|
||||
"""Application environment."""
|
||||
|
||||
DEVELOPMENT = "development"
|
||||
PRODUCTION = "production"
|
||||
TESTING = "testing"
|
||||
@@ -54,6 +56,7 @@ class Config(BaseSettings):
|
||||
Loads from environment variables and .env file.
|
||||
Domain-specific configs should be in their respective modules.
|
||||
"""
|
||||
|
||||
model_config = SettingsConfigDict(
|
||||
env_file=".env",
|
||||
env_file_encoding="utf-8",
|
||||
@@ -74,143 +77,90 @@ class Config(BaseSettings):
|
||||
|
||||
# Anthropic Configuration (Claude - cloud fallback)
|
||||
ANTHROPIC_API_KEY: str | None = Field(
|
||||
default=None,
|
||||
description="Anthropic API key for the Claude fallback backend"
|
||||
default=None, description="Anthropic API key for the Claude fallback backend"
|
||||
)
|
||||
ANTHROPIC_MODEL: str = Field(
|
||||
default="claude-sonnet-5",
|
||||
description="Claude model for the fallback backend"
|
||||
default="claude-sonnet-5", description="Claude model for the fallback backend"
|
||||
)
|
||||
PREFER_CLOUD_BACKEND: bool = Field(
|
||||
default=False,
|
||||
description="Prefer Claude over Ollama (default: local-first)"
|
||||
default=False, description="Prefer Claude over Ollama (default: local-first)"
|
||||
)
|
||||
|
||||
# Ollama Configuration (local - primary backend)
|
||||
OLLAMA_HOST: HttpUrl = Field(
|
||||
default="http://localhost:11434",
|
||||
description="Ollama server URL"
|
||||
)
|
||||
OLLAMA_DEFAULT_MODEL: str = Field(
|
||||
default="gemma4:e2b",
|
||||
description="Default Ollama model"
|
||||
)
|
||||
OLLAMA_TIMEOUT: int = Field(
|
||||
default=120,
|
||||
description="Ollama request timeout in seconds"
|
||||
)
|
||||
OLLAMA_HOST: HttpUrl = Field(default="http://localhost:11434", description="Ollama server URL")
|
||||
OLLAMA_DEFAULT_MODEL: str = Field(default="gemma4:e2b", description="Default Ollama model")
|
||||
OLLAMA_TIMEOUT: int = Field(default=120, description="Ollama request timeout in seconds")
|
||||
STEWARD_TIMEOUT: int = Field(
|
||||
default=60,
|
||||
description="Steward analysis timeout in seconds (gemma4 needs ~35s warm)"
|
||||
default=60, description="Steward analysis timeout in seconds (gemma4 needs ~35s warm)"
|
||||
)
|
||||
STREAM_TIMEOUT: int = Field(
|
||||
default=20,
|
||||
description="Timeout for each streaming turn in seconds"
|
||||
default=20, description="Timeout for each streaming turn in seconds"
|
||||
)
|
||||
|
||||
# SearXNG Configuration
|
||||
SEARXNG_HOST: HttpUrl = Field(
|
||||
default="http://searxng:8080",
|
||||
description="SearXNG server URL (container name; internal port 8080)"
|
||||
)
|
||||
SEARXNG_TIMEOUT: int = Field(
|
||||
default=30,
|
||||
description="SearXNG request timeout in seconds"
|
||||
description="SearXNG server URL (container name; internal port 8080)",
|
||||
)
|
||||
SEARXNG_TIMEOUT: int = Field(default=30, description="SearXNG request timeout in seconds")
|
||||
|
||||
# Redis Configuration
|
||||
REDIS_HOST: str = Field(
|
||||
default="localhost",
|
||||
description="Redis server host"
|
||||
)
|
||||
REDIS_PORT: int = Field(
|
||||
default=6379,
|
||||
description="Redis server port"
|
||||
)
|
||||
REDIS_TIMEOUT: int = Field(
|
||||
default=5,
|
||||
description="Redis connection timeout in seconds"
|
||||
)
|
||||
REDIS_HOST: str = Field(default="localhost", description="Redis server host")
|
||||
REDIS_PORT: int = Field(default=6379, description="Redis server port")
|
||||
REDIS_TIMEOUT: int = Field(default=5, description="Redis connection timeout in seconds")
|
||||
|
||||
# Library-Desk Configuration (The Librarian backend)
|
||||
LIBRARIAN_TIMEOUT: int = Field(
|
||||
default=180,
|
||||
description="Total time budget for a librarian delegation in seconds"
|
||||
default=180, description="Total time budget for a librarian delegation in seconds"
|
||||
)
|
||||
LIBRARY_DESK_HOST: HttpUrl = Field(
|
||||
default="http://library-desk:8089",
|
||||
description="Library-Desk API URL (container name; internal port 8089)"
|
||||
description="Library-Desk API URL (container name; internal port 8089)",
|
||||
)
|
||||
LIBRARY_DESK_API_KEY: str = Field(
|
||||
default="",
|
||||
description="API key for Library-Desk authentication"
|
||||
default="", description="API key for Library-Desk authentication"
|
||||
)
|
||||
LIBRARY_DESK_TIMEOUT: int = Field(
|
||||
default=60,
|
||||
description="Library-Desk request timeout in seconds"
|
||||
default=60, description="Library-Desk request timeout in seconds"
|
||||
)
|
||||
|
||||
# Core-API Configuration (The Housekeeper backend)
|
||||
CORE_API_HOST: HttpUrl = Field(
|
||||
default="http://core-api:8083",
|
||||
description="Core-API URL for Home Assistant integration (container name; internal port 8083)"
|
||||
)
|
||||
CORE_API_KEY: str = Field(
|
||||
default="",
|
||||
description="API key for Core-API authentication"
|
||||
)
|
||||
CORE_API_TIMEOUT: int = Field(
|
||||
default=30,
|
||||
description="Core-API request timeout in seconds"
|
||||
description="Core-API URL for Home Assistant integration (container name; internal port 8083)",
|
||||
)
|
||||
CORE_API_KEY: str = Field(default="", description="API key for Core-API authentication")
|
||||
CORE_API_TIMEOUT: int = Field(default=30, description="Core-API request timeout in seconds")
|
||||
|
||||
# Qdrant Configuration (Memory vector storage)
|
||||
QDRANT_HOST: str = Field(
|
||||
default="localhost",
|
||||
description="Qdrant server host"
|
||||
)
|
||||
QDRANT_PORT: int = Field(
|
||||
default=6333,
|
||||
description="Qdrant server port"
|
||||
)
|
||||
QDRANT_HOST: str = Field(default="localhost", description="Qdrant server host")
|
||||
QDRANT_PORT: int = Field(default=6333, description="Qdrant server port")
|
||||
QDRANT_EMBEDDING_DIM: int = Field(
|
||||
default=768,
|
||||
description="Embedding dimension (768 for nomic-embed-text)"
|
||||
default=768, description="Embedding dimension (768 for nomic-embed-text)"
|
||||
)
|
||||
|
||||
# Ollama Embedding Configuration
|
||||
OLLAMA_EMBEDDING_MODEL: str = Field(
|
||||
default="nomic-embed-text",
|
||||
description="Ollama model for embeddings"
|
||||
default="nomic-embed-text", description="Ollama model for embeddings"
|
||||
)
|
||||
|
||||
# Redis Memory Database
|
||||
REDIS_MEMORY_DB: int = Field(
|
||||
default=1,
|
||||
description="Redis database number for memory cache"
|
||||
)
|
||||
REDIS_MEMORY_TTL_HOURS: int = Field(
|
||||
default=24,
|
||||
description="TTL for session context in hours"
|
||||
)
|
||||
REDIS_MEMORY_DB: int = Field(default=1, description="Redis database number for memory cache")
|
||||
REDIS_MEMORY_TTL_HOURS: int = Field(default=24, description="TTL for session context in hours")
|
||||
|
||||
# Logging
|
||||
LOG_LEVEL: str | None = Field(
|
||||
default=None,
|
||||
description="Logging level (auto-set based on environment if not specified)"
|
||||
default=None, description="Logging level (auto-set based on environment if not specified)"
|
||||
)
|
||||
|
||||
# User Configuration
|
||||
DEFAULT_USER: str | None = Field(
|
||||
default=None,
|
||||
description="Default user for single-user setup (auto-set based on environment if not specified)"
|
||||
description="Default user for single-user setup (auto-set based on environment if not specified)",
|
||||
)
|
||||
|
||||
# CORS
|
||||
CORS_ORIGINS: list[str] = Field(
|
||||
default=["*"],
|
||||
description="Allowed CORS origins"
|
||||
)
|
||||
CORS_ORIGINS: list[str] = Field(default=["*"], description="Allowed CORS origins")
|
||||
CORS_ALLOW_CREDENTIALS: bool = True
|
||||
CORS_ALLOW_METHODS: list[str] = ["*"]
|
||||
CORS_ALLOW_HEADERS: list[str] = ["*"]
|
||||
@@ -235,8 +185,7 @@ class Config(BaseSettings):
|
||||
if (
|
||||
self.ENVIRONMENT != Environment.PRODUCTION
|
||||
and self.DEFAULT_USER is not None
|
||||
and sanitize_user_id(self.DEFAULT_USER)
|
||||
== sanitize_user_id(PRODUCTION_TENANT)
|
||||
and sanitize_user_id(self.DEFAULT_USER) == sanitize_user_id(PRODUCTION_TENANT)
|
||||
):
|
||||
raise ValueError(
|
||||
f"Refusing to start: ENVIRONMENT={self.ENVIRONMENT.value} is "
|
||||
@@ -299,8 +248,7 @@ class Config(BaseSettings):
|
||||
return self.DEFAULT_USER or PRODUCTION_TENANT
|
||||
|
||||
if self.DEFAULT_USER is not None and (
|
||||
self.DEFAULT_USER == TEST_TENANT
|
||||
or self.DEFAULT_USER.startswith(TEST_TENANT_PREFIX)
|
||||
self.DEFAULT_USER == TEST_TENANT or self.DEFAULT_USER.startswith(TEST_TENANT_PREFIX)
|
||||
):
|
||||
return self.DEFAULT_USER
|
||||
return TEST_TENANT
|
||||
|
||||
Reference in New Issue
Block a user