diff --git a/routes/model_routes.py b/routes/model_routes.py index a92f06b..44b4abd 100644 --- a/routes/model_routes.py +++ b/routes/model_routes.py @@ -1402,12 +1402,18 @@ def setup_model_routes(model_discovery): return sess in variants or sess.startswith(base + "/") def _clear_sessions_for_endpoint(db, base_url: str) -> int: + """Drop stored auth for sessions using an endpoint being deleted. + + Keep the session's endpoint URL and model intact. If the admin is + replacing an endpoint with the same URL, clearing those fields leaves + the UI looking selected while chat requests arrive with an empty model. + The chat-time orphan guard still clears truly dead endpoints when no + matching enabled endpoint exists. + """ cleared = 0 rows = db.query(DbSession).filter(DbSession.endpoint_url.isnot(None)).all() for row in rows: if _session_uses_endpoint_url(row.endpoint_url or "", base_url): - row.endpoint_url = "" - row.model = "" row.headers = {} row.updated_at = datetime.utcnow() cleared += 1 @@ -1425,8 +1431,6 @@ def setup_model_routes(model_discovery): try: for sess in list(getattr(manager, "sessions", {}).values()): if _session_uses_endpoint_url(getattr(sess, "endpoint_url", "") or "", base_url): - sess.endpoint_url = "" - sess.model = "" sess.headers = {} cleared += 1 except Exception: diff --git a/src/endpoint_resolver.py b/src/endpoint_resolver.py index b204c7c..72cd054 100644 --- a/src/endpoint_resolver.py +++ b/src/endpoint_resolver.py @@ -35,6 +35,18 @@ def _first_chat_model(models) -> Optional[str]: return (models[0] if models else None) +def _endpoint_cached_models(ep) -> list: + """Return cached model ids from the current or legacy endpoint field.""" + raw = getattr(ep, "cached_models", None) or getattr(ep, "models", None) + if not raw: + return [] + try: + models = json.loads(raw) if isinstance(raw, str) else raw + except Exception: + return [] + return models if isinstance(models, list) else [] + + # Cache for Tailscale hostname → IP resolution _tailscale_cache: Dict[str, Optional[str]] = {} @@ -236,14 +248,9 @@ def resolve_endpoint( chat_url = build_chat_url(base) headers = build_headers(ep.api_key, base) - # If no model specified, try to pick the first from endpoint's cached list - if not model and hasattr(ep, 'models') and ep.models: - try: - models = json.loads(ep.models) if isinstance(ep.models, str) else ep.models - if models: - model = _first_chat_model(models) - except Exception: - pass + # If no model specified, try to pick the first from endpoint's cached list. + if not model: + model = _first_chat_model(_endpoint_cached_models(ep)) or "" return chat_url, model or fallback_model, headers except Exception as e: @@ -275,13 +282,8 @@ def resolve_endpoint_by_id( chat_url = build_chat_url(base) headers = build_headers(ep.api_key, base) m = (model or "").strip() - if not m and getattr(ep, "models", None): - try: - models = json.loads(ep.models) if isinstance(ep.models, str) else ep.models - if models: - m = _first_chat_model(models) or "" - except Exception: - pass + if not m: + m = _first_chat_model(_endpoint_cached_models(ep)) or "" if not m: return None return chat_url, m, headers