150 lines
6 KiB
Python
150 lines
6 KiB
Python
"""Konfiguration nur über Umgebungsvariablen mit Präfix AIW_ (oder .env)."""
|
|
|
|
from functools import lru_cache
|
|
|
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
|
|
|
|
class Settings(BaseSettings):
|
|
model_config = SettingsConfigDict(env_prefix="AIW_", env_file=".env", extra="ignore")
|
|
|
|
database_url: str = "postgresql+psycopg://aiw:aiw@127.0.0.1:55433/aiw"
|
|
|
|
# Demo-Anmeldung (→ Konzept 5.1): ein gemeinsames Passwort für alle Demo-Nutzer.
|
|
# Leer = Demo-Anmeldung abgeschaltet.
|
|
demo_password: str = ""
|
|
# Cookies nur über HTTPS; lokal ohne TLS auf False setzen
|
|
cookie_secure: bool = True
|
|
session_hours: int = 12
|
|
# Sperre nach Fehlversuchen (eigene Passwörter)
|
|
login_max_failures: int = 5
|
|
login_lock_minutes: int = 15
|
|
|
|
# Git-Quellen (→ Konzept 7.3, 7.5): erlaubte Hosts, kommagetrennt.
|
|
# file:// nur, wenn ausdrücklich erlaubt (lokale Test-Repositories).
|
|
git_allowed_hosts: str = ""
|
|
git_allow_local: bool = False
|
|
git_timeout_seconds: int = 20
|
|
# Lesender Zugriff (→ Konzept 7.5): Klon-Cache und Limits
|
|
git_cache_dir: str = "data/git-cache"
|
|
git_max_repo_mb: int = 500
|
|
git_max_file_kb: int = 1024
|
|
# Commits für Änderungsvorschläge (→ Konzept 7.5)
|
|
git_author_name: str = "AI Workspace"
|
|
git_author_email: str = "ai-workspace@localhost"
|
|
git_max_change_files: int = 50
|
|
pr_timeout_seconds: float = 20.0
|
|
# Offene Pull Requests so oft abfragen (Status, Kommentare)
|
|
pr_poll_seconds: int = 300
|
|
|
|
# Datenbank-Verbindungen (MCP über die DB-Dienste, → Konzept 7.4): erlaubte Datenbank-Hosts, kommagetrennt;
|
|
# localhost nur, wenn ausdrücklich erlaubt. Zusätzlich prüft der DB-Dienst seine eigene Liste.
|
|
db_allowed_hosts: str = ""
|
|
db_allow_local: bool = False
|
|
|
|
# Zentrale MCP-Server (→ Konzept 7.3): nur diese Hosts; http nur für localhost und nur wenn erlaubt
|
|
mcp_allowed_hosts: str = ""
|
|
mcp_allow_local: bool = False
|
|
mcp_timeout_seconds: float = 30.0
|
|
# Hugin (→ Konzept 7.9): Host unter Administration → Hugin, Integrations-Key je Workspace;
|
|
# diese Adresse füllt das Formular nur vor. Hosts wie bei MCP (AIW_MCP_ALLOWED_HOSTS).
|
|
hugin_url: str = ""
|
|
hugin_timeout_seconds: float = 15.0
|
|
# Abgleich im Hintergrund (nur anzeigen und benachrichtigen, nie übernehmen); 0 = aus
|
|
hugin_check_hours: int = 24
|
|
# Größtes Paket (ZIP im Quellformat), das ein Workspace festschreibt
|
|
hugin_max_package_kb: int = 1024
|
|
|
|
# Uploads mit DuckDB-Analyse (→ Konzept 7.7)
|
|
upload_dir: str = "data/uploads"
|
|
upload_max_mb: int = 200
|
|
# Abgeglichene Ordner (app.documents): Größe je Datei, Dateien je Ordner, Zeit für die Auslese, Text je Datei
|
|
doc_max_mb: int = 25
|
|
doc_max_files: int = 2000
|
|
doc_extract_timeout_seconds: float = 120.0
|
|
doc_max_text_kb: int = 2048
|
|
# Speicherkontingent je Workspace (DuckDB-Dateien und Text abgeglichener Ordner); je Workspace anpassbar
|
|
workspace_storage_mb: int = 500
|
|
query_timeout_seconds: float = 20.0
|
|
query_max_rows: int = 200
|
|
query_memory_mb: int = 512
|
|
|
|
# Währung der Modellpreise (nur Anzeige)
|
|
cost_currency: str = "USD"
|
|
|
|
# Benachrichtigungen (E-Mail per SMTP, Webhooks für Teams/Slack); Links zeigen auf public_url
|
|
public_url: str = ""
|
|
smtp_host: str = ""
|
|
smtp_port: int = 587
|
|
smtp_user: str = ""
|
|
smtp_password: str = ""
|
|
smtp_from: str = ""
|
|
smtp_starttls: bool = True
|
|
smtp_timeout_seconds: float = 10.0
|
|
# Kommagetrennt; ".example.com" erlaubt alle Unterdomains
|
|
webhook_allowed_hosts: str = "hooks.slack.com,.webhook.office.com,.logic.azure.com"
|
|
webhook_allow_local: bool = False
|
|
|
|
# Betrieb: Logs (text | json), Metriken (/metrics nur mit Token), Worker-HTTP für Probes
|
|
log_level: str = "INFO"
|
|
log_format: str = "text"
|
|
metrics_token: str = ""
|
|
worker_http_host: str = "0.0.0.0"
|
|
worker_http_port: int = 9101
|
|
# Worker gilt als hängend bzw. tot, wenn seine Schleife bzw. sein Herzschlag älter ist
|
|
worker_stale_seconds: int = 120
|
|
|
|
# Gelöschte Workspaces bleiben so viele Tage im Papierkorb, danach löscht der Worker sie endgültig
|
|
workspace_trash_days: int = 14
|
|
|
|
# Freigaben (→ Konzept 10.5): Ablauffrist in Stunden
|
|
approval_hours: int = 24
|
|
|
|
# Tools (→ Konzept 8.3): Ergebnisgröße und Zahl der Tool-Runden je Run
|
|
tool_max_output_chars: int = 20000
|
|
max_tool_rounds: int = 12
|
|
# Obergrenze, bis zu der Workspace-Admins die Tool-Runden je Antwort erhöhen dürfen
|
|
max_tool_rounds_limit: int = 40
|
|
# Verlauf je Anfrage höchstens so viele Tokens (geschätzt) bzw. 60 % des Kontextfensters;
|
|
# Älteres geht als Arbeitsnotiz (Zusammenfassung) mit
|
|
history_max_tokens: int = 60000
|
|
|
|
# Worker (→ Konzept 9.3)
|
|
run_lease_seconds: int = 60
|
|
run_max_attempts: int = 3
|
|
max_runs_per_team: int = 3
|
|
worker_poll_seconds: float = 1.0
|
|
|
|
# Master-Key für Geheimnisse in der Datenbank (aiw gen-key); kommagetrennt zum Wechseln
|
|
secret_key: str = ""
|
|
# Zeitlimit für einen Modellaufruf (Sekunden)
|
|
model_timeout_seconds: float = 120.0
|
|
|
|
# Streaming (→ Konzept 4.4): Tokens gebündelt schreiben
|
|
event_flush_ms: int = 150
|
|
|
|
@property
|
|
def allowed_git_hosts(self) -> set[str]:
|
|
return {h.strip().lower() for h in self.git_allowed_hosts.split(",") if h.strip()}
|
|
|
|
@property
|
|
def allowed_db_hosts(self) -> set[str]:
|
|
return {h.strip().lower() for h in self.db_allowed_hosts.split(",") if h.strip()}
|
|
|
|
@property
|
|
def allowed_webhook_hosts(self) -> set[str]:
|
|
return {h.strip().lower() for h in self.webhook_allowed_hosts.split(",") if h.strip()}
|
|
|
|
@property
|
|
def allowed_mcp_hosts(self) -> set[str]:
|
|
return {h.strip().lower() for h in self.mcp_allowed_hosts.split(",") if h.strip()}
|
|
|
|
@property
|
|
def psycopg_url(self) -> str:
|
|
"""URL für psycopg direkt (LISTEN), ohne den SQLAlchemy-Treiberzusatz."""
|
|
return self.database_url.replace("postgresql+psycopg://", "postgresql://", 1)
|
|
|
|
|
|
@lru_cache
|
|
def get_settings() -> Settings:
|
|
return Settings()
|