Phase 8: TypeScript migration, i18n rewrite, Activity Tree, Projects API, Heartbeats

This commit is contained in:
Rose
2026-04-29 11:50:00 +02:00
parent c705fad626
commit 255914c9f1
43 changed files with 17948 additions and 6899 deletions

View File

@@ -1033,6 +1033,18 @@ def get_available_models() -> dict:
logger.debug("Live models fetched for %s: %s", pid, _live_ids)
except Exception as _e:
logger.debug("Could not fetch live models for %s: %s", pid, _e)
# Fallback: read models from config.yaml providers.<pid>.models
if not raw_models:
try:
_prov_cfg = cfg.get("providers", {}).get(pid, {})
if isinstance(_prov_cfg, dict):
_cfg_models = _prov_cfg.get("models", [])
if isinstance(_cfg_models, list):
raw_models = [{"id": m, "label": m.split("/")[-1] if "/" in m else m} for m in _cfg_models if isinstance(m, str)]
if raw_models:
logger.debug("Loaded %d models from config for %s", len(raw_models), pid)
except Exception as _e:
logger.debug("Could not read config models for %s: %s", pid, _e)
_active = (active_provider or "").lower()
if _active and pid != _active:
models = []
@@ -1136,7 +1148,7 @@ def get_available_models() -> dict:
_INDEX_HTML_PATH = REPO_ROOT / "static" / "index.html"
# ── Thread synchronisation ───────────────────────────────────────────────────
LOCK = threading.Lock()
LOCK = threading.RLock() # Reentrant — allows nested acquisition in save() → _write_session_index()
SESSIONS_MAX = 100
CHAT_LOCK = threading.Lock()
STREAMS: dict = {}
@@ -1188,6 +1200,8 @@ _SETTINGS_DEFAULTS = {
"sound_enabled": False, # play notification sound when assistant finishes
"notifications_enabled": False, # browser notification when tab is in background
"bubble_layout": False, # right-aligned user / left-aligned assistant chat bubbles
"user_emoji": "🙂", # emoji shown for user messages in chat
"user_name": "You", # name shown for user messages in chat
"password_hash": None, # PBKDF2-HMAC-SHA256 hash; None = auth disabled
}
_SETTINGS_LEGACY_DROP_KEYS = {"assistant_language"}
@@ -1198,7 +1212,7 @@ def load_settings() -> dict:
settings = dict(_SETTINGS_DEFAULTS)
if SETTINGS_FILE.exists():
try:
stored = json.loads(SETTINGS_FILE.read_text(encoding="utf-8"))
with SETTINGS_FILE.open(encoding="utf-8") as _f: stored = json.loads(_f.read())
if isinstance(stored, dict):
settings.update(
{