109 lines
4.0 KiB
Python
109 lines
4.0 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
|
|
readonly_sandbox: str
|
|
write_sandbox: str
|
|
resume_json_flag_style: str
|
|
allow_plain_text: bool
|
|
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,
|
|
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),
|
|
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()),
|
|
)
|