File size: 2,709 Bytes
35c0d38 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | """Application configuration.
Loads settings and secrets from environment variables (and the local .env file)
using pydantic-settings. Everything the rest of the app needs — API keys, model
names, the SQLite path, generation tunables — lives here, so no other module
ever has to touch os.environ directly.
Usage:
from src.config import settings
settings.anthropic_api_key
"""
from __future__ import annotations
import os
from pydantic_settings import BaseSettings, SettingsConfigDict
# pydantic-settings ranks real environment variables ABOVE the .env file. Some
# shells/CI (including the dev environment this was built in) export an *empty*
# ANTHROPIC_API_KEY, which would silently shadow the real value in .env. Drop
# any of our secrets that are present-but-empty so .env can fill them in. This
# is safe on Hugging Face Spaces, where secrets arrive as non-empty env vars and
# therefore still take priority.
_SECRET_ENV_VARS = (
"ANTHROPIC_API_KEY",
"HF_TOKEN",
"LANGFUSE_PUBLIC_KEY",
"LANGFUSE_SECRET_KEY",
"LANGFUSE_HOST",
"TAVILY_API_KEY",
)
for _key in _SECRET_ENV_VARS:
if os.environ.get(_key, None) == "":
del os.environ[_key]
class Settings(BaseSettings):
"""Typed view over the .env file / environment variables.
Secrets default to empty strings so that *importing* this module never
fails just because a key is missing. Each assistant/tool checks that the
key it needs is actually present at call time and raises a clear error if
not. This keeps the smoke tests and partial setups working.
"""
model_config = SettingsConfigDict(
env_file=".env",
env_file_encoding="utf-8",
extra="ignore", # ignore unrelated env vars instead of erroring
)
# --- Secrets (loaded from .env) ---
anthropic_api_key: str = ""
hf_token: str = ""
langfuse_public_key: str = ""
langfuse_secret_key: str = ""
langfuse_host: str = "https://cloud.langfuse.com"
tavily_api_key: str = ""
# --- Model identifiers ---
# Frontier assistant (and the eval judge) use Claude Sonnet 4.5.
frontier_model: str = "claude-sonnet-4-5"
# Output-moderation guardrail uses the cheaper/faster Haiku.
moderation_model: str = "claude-haiku-4-5"
# Open-source assistant.
oss_model: str = "Qwen/Qwen2.5-1.5B-Instruct"
# --- Generation tunables (shared by both assistants for fair comparison) ---
max_tokens: int = 512
temperature: float = 0.7
# --- Storage ---
# SQLite file backing the per-session chat memory (added in Phase 3).
sqlite_path: str = "./data/sessions.db"
# Single shared instance imported across the app.
settings = Settings()
|