Add `DEVIN_MODE` configuration supporting `enterprise` (default) and `organization_sessions` modes. Organization sessions mode uses `/v3/organizations/{org_id}/sessions` API with `ViewOrgSessions` permission, suitable for non-Enterprise organizations. Sums session ACUs consumed within configurable rolling window (1-365 days via `DEVIN_SESSION_WINDOW_DAYS`). Mode does not show quota, percentage, credit, or reset fields as these are unav
64 lines
1.9 KiB
Python
64 lines
1.9 KiB
Python
from functools import lru_cache
|
|
from typing import Literal
|
|
from zoneinfo import ZoneInfo, ZoneInfoNotFoundError
|
|
|
|
from pydantic import SecretStr, field_validator
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(env_file='.env', env_file_encoding='utf-8', extra='ignore', case_sensitive=False)
|
|
|
|
host: str = '0.0.0.0'
|
|
port: int = 8080
|
|
codex_enabled: bool = True
|
|
codex_command: str = 'codex'
|
|
codex_timeout: float = 8
|
|
devin_enabled: bool = True
|
|
devin_api_key: SecretStr = SecretStr('')
|
|
devin_api_url: str = 'https://api.devin.ai'
|
|
devin_mode: Literal['enterprise', 'organization_sessions'] = 'enterprise'
|
|
devin_org_id: str = ''
|
|
devin_user_id: str = ''
|
|
devin_session_window_days: int = 30
|
|
devin_timeout: float = 8
|
|
provider_cache_ttl: float = 8
|
|
refresh_interval: int = 10
|
|
timezone: str = 'Europe/Vienna'
|
|
demo_mode: bool = False
|
|
|
|
@field_validator('codex_timeout', 'devin_timeout', 'provider_cache_ttl')
|
|
@classmethod
|
|
def positive(cls, value: float) -> float:
|
|
if value <= 0:
|
|
raise ValueError('must be positive')
|
|
return value
|
|
|
|
@field_validator('refresh_interval')
|
|
@classmethod
|
|
def positive_interval(cls, value: int) -> int:
|
|
if value < 1:
|
|
raise ValueError('must be at least 1')
|
|
return value
|
|
|
|
@field_validator('devin_session_window_days')
|
|
@classmethod
|
|
def valid_session_window(cls, value: int) -> int:
|
|
if not 1 <= value <= 365:
|
|
raise ValueError('must be between 1 and 365')
|
|
return value
|
|
|
|
@field_validator('timezone')
|
|
@classmethod
|
|
def valid_timezone(cls, value: str) -> str:
|
|
try:
|
|
ZoneInfo(value)
|
|
except ZoneInfoNotFoundError as exc:
|
|
raise ValueError('invalid timezone') from exc
|
|
return value
|
|
|
|
|
|
@lru_cache
|
|
def get_settings() -> Settings:
|
|
return Settings()
|