config.py 2.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. from __future__ import annotations
  2. from functools import lru_cache
  3. from pathlib import Path
  4. from typing import Self
  5. from pydantic import Field, model_validator
  6. from pydantic_settings import BaseSettings, SettingsConfigDict
  7. from supply_agent.paths import resolve_path
  8. class Settings(BaseSettings):
  9. """Application settings loaded from environment variables or .env file."""
  10. model_config = SettingsConfigDict(
  11. env_file=".env",
  12. env_file_encoding="utf-8",
  13. extra="ignore",
  14. )
  15. # OpenRouter
  16. openrouter_api_key: str = Field(..., alias="OPENROUTER_API_KEY")
  17. openrouter_model: str = Field(
  18. default="google/gemini-2.5-flash",
  19. alias="OPENROUTER_MODEL",
  20. )
  21. openrouter_base_url: str = Field(
  22. default="https://openrouter.ai/api/v1",
  23. alias="OPENROUTER_BASE_URL",
  24. )
  25. openrouter_site_url: str = Field(default="", alias="OPENROUTER_SITE_URL")
  26. openrouter_site_name: str = Field(default="SupplyAgent", alias="OPENROUTER_SITE_NAME")
  27. openrouter_timeout_seconds: float = Field(
  28. default=120.0,
  29. alias="OPENROUTER_TIMEOUT_SECONDS",
  30. )
  31. # Agent
  32. agent_max_iterations: int = Field(default=20, alias="AGENT_MAX_ITERATIONS")
  33. agent_temperature: float = Field(default=0.7, alias="AGENT_TEMPERATURE")
  34. find_agent_timeout_seconds: float = Field(
  35. default=1800.0,
  36. ge=60.0,
  37. le=7200.0,
  38. alias="FIND_AGENT_TIMEOUT_SECONDS",
  39. )
  40. # Skills
  41. skills_dir: Path = Field(default=Path("skills"), alias="SKILLS_DIR")
  42. # Logging
  43. logs_dir: Path = Field(default=Path("logs"), alias="LOGS_DIR")
  44. log_enabled: bool = Field(default=True, alias="LOG_ENABLED")
  45. @model_validator(mode="after")
  46. def resolve_relative_paths(self) -> Self:
  47. """Resolve skills_dir and logs_dir against project root when needed."""
  48. self.skills_dir = resolve_path(self.skills_dir)
  49. self.logs_dir = resolve_path(self.logs_dir)
  50. return self
  51. @classmethod
  52. def from_env(cls, **overrides: object) -> Self:
  53. """Create settings with optional overrides (useful for testing)."""
  54. return cls(**overrides) # type: ignore[arg-type]
  55. @lru_cache
  56. def get_settings() -> Settings:
  57. return Settings() # type: ignore[call-arg]