"""Environment-driven settings. A *backend* is one place to send LLM calls: a wire protocol + endpoint + model + key. The default backend comes from the LLM_* env vars; tasks can opt into a named backend (see `backend()`), so some demos can run on Anthropic-direct while others run on an Oumi deployment. Each backend has a provider (wire protocol): - "openai": OpenAI Chat Completions. base_url ends in /v1/ (the SDK appends chat/completions). Works for Anthropic's OpenAI-compat endpoint and Oumi deployments served as OpenAI-compatible (e.g. tuned open-weight models). - "anthropic": Anthropic Messages. base_url ends in /inference (the SDK appends /v1/messages). Required for Oumi deployments that proxy an Anthropic model -- Oumi's /chat/completions rejects the "anthropic" provider. """ import os from dataclasses import dataclass from pathlib import Path APP_VERSION = "0.1.0" REPO_ROOT = Path(__file__).resolve().parent.parent DATA_DIR = REPO_ROOT / "data" STATIC_DIR = REPO_ROOT / "app" / "static" @dataclass(frozen=True) class Backend: provider: str # "openai" | "anthropic" base_url: str model: str api_key: str name: str = "default" # profile that actually served the call (traces tag this) # Default backend (the whole app's backend unless a task names another). DEFAULT_BACKEND = Backend( provider=os.environ.get("LLM_PROVIDER", "openai"), base_url=os.environ.get("LLM_BASE_URL", "https://api.anthropic.com/v1/"), model=os.environ.get("LLM_MODEL", "claude-haiku-4-5"), api_key=os.environ.get("LLM_API_KEY") or os.environ.get("ANTHROPIC_API_KEY", ""), ) def backend(name: str | None = None) -> Backend: """Resolve a task's backend by name. `None`/empty -> the default backend. A named backend "foo" is read from LLM_FOO_PROVIDER / LLM_FOO_BASE_URL / LLM_FOO_MODEL / LLM_FOO_API_KEY (PROVIDER defaults to "openai"). If a named backend isn't fully configured (base_url / model / api_key all set), we fall back to the default — so a task pinned to "oumi" still runs in a dev env that hasn't set LLM_OUMI_*. The returned backend carries the name that actually served the call, so a silent fallback (e.g. a mistyped Space secret) is visible in the traces. """ if not name: return DEFAULT_BACKEND p = f"LLM_{name.upper()}_" base_url = os.environ.get(p + "BASE_URL") model = os.environ.get(p + "MODEL") api_key = os.environ.get(p + "API_KEY") if not (base_url and model and api_key): return DEFAULT_BACKEND return Backend( provider=os.environ.get(p + "PROVIDER", "openai"), base_url=base_url, model=model, api_key=api_key, name=name.lower(), ) # Back-compat alias for the default model id (used by /api/health). LLM_MODEL = DEFAULT_BACKEND.model # Shared passcode gating /api/* (except /api/health). Empty string disables the gate. APP_PASSCODE = os.environ.get("APP_PASSCODE", "") MAX_TOOL_ITERATIONS = 6