Files
nas_connection/app/config.py

113 lines
4.2 KiB
Python

from __future__ import annotations
import os
from dataclasses import dataclass
from pathlib import Path
from dotenv import load_dotenv
def _bool_env(name: str, default: bool) -> bool:
raw = os.getenv(name)
if raw is None:
return default
return raw.strip().lower() in {"1", "true", "yes", "y", "on"}
def _int_env(name: str, default: int) -> int:
raw = os.getenv(name)
if not raw:
return default
return int(raw)
def _id_set(name: str) -> set[int]:
raw = os.getenv(name, "")
ids: set[int] = set()
for part in raw.replace(";", ",").split(","):
part = part.strip()
if not part:
continue
ids.add(int(part))
return ids
@dataclass(frozen=True)
class Config:
telegram_bot_token: str
allowed_user_ids: set[int]
state_path: Path
workspace_root: Path
codex_bin: str
codex_timeout_seconds: int
codex_backend: str
app_server_url: str
app_server_model: str | None
app_server_reasoning_effort: str | None
app_server_speed_mode: str
assistant_sandbox: str
readonly_sandbox: str
write_sandbox: str
resume_json_flag_style: str
allow_plain_text: bool
work_chat_ids: set[int]
timezone: str
schedule_poll_seconds: int
persistent_ws_idle_seconds: int
gitea_base_url: str | None
gitea_username: str | None
gitea_email: str | None
gitea_default_owner: str | None
gitea_default_repo: str | None
gitea_token_configured: bool
@classmethod
def load(cls) -> "Config":
load_dotenv()
token = os.getenv("TELEGRAM_BOT_TOKEN", "").strip()
if not token:
raise RuntimeError("TELEGRAM_BOT_TOKEN is required")
backend = os.getenv("CODEX_BACKEND", "auto").strip().lower()
if backend not in {"auto", "app-server", "exec"}:
raise RuntimeError("CODEX_BACKEND must be one of: auto, app-server, exec")
app_server_model = os.getenv("CODEX_APP_SERVER_MODEL", "").strip() or "gpt-5.5"
app_server_reasoning_effort = (
os.getenv("CODEX_MODEL_REASONING_EFFORT", "").strip() or "high"
)
app_server_speed_mode = os.getenv("CODEX_SPEED_MODE", "standard").strip().lower()
if app_server_speed_mode not in {"standard", "fast"}:
raise RuntimeError("CODEX_SPEED_MODE must be one of: standard, fast")
return cls(
telegram_bot_token=token,
allowed_user_ids=_id_set("ALLOWED_TELEGRAM_USER_IDS"),
state_path=Path(os.getenv("BOT_STATE_PATH", "/app/data/state.json")),
workspace_root=Path(os.getenv("BOT_WORKSPACE_ROOT", "/workspaces")),
codex_bin=os.getenv("CODEX_BIN", "codex"),
codex_timeout_seconds=_int_env("CODEX_TIMEOUT_SECONDS", 1800),
codex_backend=backend,
app_server_url=os.getenv("CODEX_APP_SERVER_URL", "ws://127.0.0.1:4500"),
app_server_model=app_server_model,
app_server_reasoning_effort=app_server_reasoning_effort,
app_server_speed_mode=app_server_speed_mode,
assistant_sandbox=os.getenv("CODEX_ASSISTANT_SANDBOX", "read-only"),
readonly_sandbox=os.getenv("CODEX_READONLY_SANDBOX", "danger-full-access"),
write_sandbox=os.getenv("CODEX_WRITE_SANDBOX", "danger-full-access"),
resume_json_flag_style=os.getenv(
"CODEX_RESUME_JSON_FLAG_STYLE", "before_resume"
),
allow_plain_text=_bool_env("ALLOW_PLAIN_TEXT", True),
work_chat_ids=_id_set("WORK_TELEGRAM_CHAT_IDS"),
timezone=os.getenv("BOT_TIMEZONE", "Asia/Seoul"),
schedule_poll_seconds=_int_env("SCHEDULE_POLL_SECONDS", 30),
persistent_ws_idle_seconds=_int_env("PERSISTENT_WS_IDLE_SECONDS", 600),
gitea_base_url=os.getenv("GITEA_BASE_URL", "").strip() or None,
gitea_username=os.getenv("GITEA_USERNAME", "").strip() or None,
gitea_email=os.getenv("GITEA_EMAIL", "").strip() or None,
gitea_default_owner=os.getenv("GITEA_DEFAULT_OWNER", "").strip() or None,
gitea_default_repo=os.getenv("GITEA_DEFAULT_REPO", "").strip() or None,
gitea_token_configured=bool(os.getenv("GITEA_TOKEN", "").strip()),
)