Merge verified Odysseus fixes

This commit is contained in:
pewdiepie-archdaemon
2026-07-23 14:49:02 +00:00
parent 4c9a8ca115
commit d8a2059df8
117 changed files with 15693 additions and 3191 deletions
+100 -14
View File
@@ -1310,6 +1310,56 @@ def _visible_models(cached_models, hidden_models, pinned_models=None):
return [m for m in merged if m not in hidden]
def _picker_requires_pinning(base_url: str, kind: str) -> bool:
return _classify_endpoint(base_url, kind) == "api"
def _has_explicit_pinned_models(ep) -> bool:
"""Whether pinned_models was deliberately written for this endpoint.
API endpoints use pinned_models as an allow-list. An explicit empty JSON
list means "show no models"; it must not fall back to the old hidden-list
migration behavior.
"""
raw = getattr(ep, "pinned_models", None)
return raw is not None and str(raw).strip() != ""
def _legacy_visible_api_models(ep) -> List[str]:
"""Return API models selected under the old hidden-list picker.
Before API endpoints switched to an explicit allow-list, selected models
were represented as cached_models minus hidden_models. Existing OpenRouter
rows can therefore have many checked models and an empty pinned_models
field. Treat that old state as the initial pinned list so settings and chat
agree after upgrade.
"""
return _visible_models(
_cached_model_ids(ep),
getattr(ep, "hidden_models", None),
None,
)
def _picker_models_for_endpoint(ep, base_url: str, kind: str):
"""Return model IDs that should appear in the picker for an endpoint.
API providers expose remote inventory from /v1/models. Treat that cache as
inventory, not approval: only manually pinned API models should appear in
the picker. Local/self-hosted endpoints keep the older hide-list behavior.
"""
pinned = _normalize_model_ids(getattr(ep, "pinned_models", None))
if _picker_requires_pinning(base_url, kind):
if not _has_explicit_pinned_models(ep):
pinned = _legacy_visible_api_models(ep) if _hidden_model_ids(ep) else []
return pinned, pinned
return _visible_models(
_cached_model_ids(ep),
getattr(ep, "hidden_models", None),
pinned,
), pinned
def _api_key_fingerprint(api_key: Optional[str]) -> str:
"""Stable, non-secret label for distinguishing same-URL credentials."""
key = (api_key or "").strip()
@@ -1508,24 +1558,18 @@ def setup_model_routes(model_discovery):
for ep in endpoints:
base = _normalize_base(ep.base_url)
provider = _safe_detect_provider(base)
# Merge cached + pinned models, then filter out hidden ones
ep_model_type = getattr(ep, "model_type", None) or "llm"
model_ids = _visible_models(
_cached_model_ids(ep),
ep.hidden_models,
getattr(ep, "pinned_models", None),
)
# Build correct URL based on provider
chat_url = build_chat_url(base)
kind = _effective_endpoint_kind(ep, base)
category = _classify_endpoint(base, kind)
model_ids, pinned = _picker_models_for_endpoint(ep, base, kind)
if model_ids:
curated_key = _match_provider_curated(base, None)
curated, extra = _curate_models(model_ids, curated_key)
# Pinned models are admin-selected — they always belong in the
# primary curated list, not buried in extras.
pinned = _normalize_model_ids(getattr(ep, "pinned_models", None))
for m in pinned:
if m not in curated:
curated.append(m)
@@ -1887,18 +1931,24 @@ def setup_model_routes(model_discovery):
_invalidate_models_cache()
rows = db.query(ModelEndpoint).order_by(ModelEndpoint.created_at).all()
results = []
upgraded_legacy_pins = False
for r in rows:
all_models = _cached_model_ids(r)
hidden = _hidden_model_ids(r)
pinned = _normalize_model_ids(getattr(r, "pinned_models", None))
visible = _visible_models(all_models, r.hidden_models, pinned)
# Keep the list route cache-only. It feeds Settings →
# Added Models and must render immediately; explicit
# Refresh/Probe endpoints do the network work.
status = "online" if (all_models or pinned) else ("empty" if r.is_enabled else "offline")
ping = None
base = _normalize_base(r.base_url)
kind = _effective_endpoint_kind(r, base)
visible, pinned = _picker_models_for_endpoint(r, base, kind)
if _picker_requires_pinning(base, kind) and pinned and not _has_explicit_pinned_models(r):
r.pinned_models = json.dumps(pinned)
upgraded_legacy_pins = True
model_inventory_count = len(_merge_model_ids(all_models, pinned))
picker_requires_pinning = _picker_requires_pinning(base, kind)
status = "online" if (all_models or visible or pinned) else ("empty" if r.is_enabled else "offline")
results.append({
"id": r.id,
"name": r.name,
@@ -1907,6 +1957,8 @@ def setup_model_routes(model_discovery):
"api_key_fingerprint": _api_key_fingerprint(r.api_key),
"is_enabled": r.is_enabled,
"models": visible,
"model_count": model_inventory_count,
"picker_requires_pinning": picker_requires_pinning,
"pinned_models": pinned,
"hidden_count": len(hidden),
"online": status != "offline",
@@ -1920,6 +1972,9 @@ def setup_model_routes(model_discovery):
"model_refresh_interval": getattr(r, "model_refresh_interval", None),
"model_refresh_timeout": getattr(r, "model_refresh_timeout", None),
})
if upgraded_legacy_pins:
db.commit()
_invalidate_models_cache()
return results
finally:
db.close()
@@ -2023,6 +2078,10 @@ def setup_model_routes(model_discovery):
if refresh_timeout is not None:
existing.model_refresh_timeout = refresh_timeout
changed = True
incoming_model_type = (model_type or "").strip() or "llm"
if incoming_model_type and (getattr(existing, "model_type", None) or "llm") != incoming_model_type:
existing.model_type = incoming_model_type
changed = True
if api_key.strip() and not existing.api_key:
existing.api_key = api_key.strip()
changed = True
@@ -2255,9 +2314,10 @@ def setup_model_routes(model_discovery):
raise HTTPException(404, "Endpoint not found")
hidden = _hidden_model_ids(ep)
all_models = _cached_model_ids(ep)
base = _normalize_base(ep.base_url)
kind = _effective_endpoint_kind(ep, base)
picker_requires_pinning = _picker_requires_pinning(base, kind)
if refresh:
base = _normalize_base(ep.base_url)
kind = _effective_endpoint_kind(ep, base)
category = _classify_endpoint(base, kind)
timeout = _manual_refresh_timeout(ep, category, refresh_timeout)
try:
@@ -2276,6 +2336,8 @@ def setup_model_routes(model_discovery):
response.headers["X-Model-Refresh-Status"] = "failed"
response.headers["X-Model-Refresh-Warning"] = "Model refresh failed or returned no models; kept cached models."
pinned = _normalize_model_ids(getattr(ep, "pinned_models", None))
if picker_requires_pinning and not _has_explicit_pinned_models(ep):
pinned = _legacy_visible_api_models(ep)
pinned_set = set(pinned)
return [
{
@@ -2283,6 +2345,7 @@ def setup_model_routes(model_discovery):
"display": m.split("/")[-1],
"is_hidden": m in hidden,
"is_pinned": m in pinned_set,
"picker_requires_pinning": picker_requires_pinning,
}
for m in _merge_model_ids(all_models, pinned)
]
@@ -2311,11 +2374,28 @@ def setup_model_routes(model_discovery):
hidden = body.get("hidden")
if not isinstance(hidden, list):
raise HTTPException(400, "hidden must be a list of model IDs")
ep.hidden_models = json.dumps(hidden) if hidden else None
base = _normalize_base(ep.base_url)
kind = _effective_endpoint_kind(ep, base)
if _picker_requires_pinning(base, kind):
# Compatibility for older/admin UI paths that still submit
# the previous hide-list shape. API pickers are allow-lists:
# convert "unchecked models" into an explicit pinned list so
# Settings summary, /api/models, and chat agree.
selected = _visible_models(_cached_model_ids(ep), hidden, None)
ep.pinned_models = json.dumps(selected)
ep.hidden_models = None
else:
ep.hidden_models = json.dumps(hidden) if hidden else None
# Accept either "pinned" or "pinned_models" for the manual IDs list.
if "pinned_models" in body or "pinned" in body:
pinned = _normalize_model_ids(body.get("pinned_models", body.get("pinned")))
ep.pinned_models = json.dumps(pinned) if pinned else None
base = _normalize_base(ep.base_url)
kind = _effective_endpoint_kind(ep, base)
if _picker_requires_pinning(base, kind):
ep.pinned_models = json.dumps(pinned)
ep.hidden_models = None
else:
ep.pinned_models = json.dumps(pinned) if pinned else None
db.commit()
_invalidate_models_cache()
hidden_count = len(json.loads(ep.hidden_models)) if ep.hidden_models else 0
@@ -2468,7 +2548,13 @@ def setup_model_routes(model_discovery):
ep.model_type = body["model_type"].strip() or ep.model_type
if "pinned_models" in body:
_pinned = _normalize_model_ids(body["pinned_models"])
ep.pinned_models = json.dumps(_pinned) if _pinned else None
_base_for_pins = _normalize_base(ep.base_url)
_kind_for_pins = _effective_endpoint_kind(ep, _base_for_pins)
if _picker_requires_pinning(_base_for_pins, _kind_for_pins):
ep.pinned_models = json.dumps(_pinned)
ep.hidden_models = None
else:
ep.pinned_models = json.dumps(_pinned) if _pinned else None
if "endpoint_kind" in body:
ep.endpoint_kind = _normalize_endpoint_kind(body.get("endpoint_kind"))
if "model_refresh_mode" in body: