fix(inventory): deduplicate models between user-defined and aggregator providers
When a user-defined provider (e.g. litellm-proxy) and an aggregator (e.g. openrouter) both advertise the same model name, the Desktop/TUI model picker would show the model under both groups. Selecting it from the aggregator row silently set model.provider to the aggregator, breaking calls because the aggregator doesn't actually serve that model ID. Fix: after list_authenticated_providers() returns, collect all models from user-defined provider rows and filter them out of aggregator rows. Uses is_aggregator() from hermes_cli/providers.py to identify aggregators. Case-insensitive matching. Fixes #45954
This commit is contained in:
@@ -157,6 +157,36 @@ def build_models_payload(
|
||||
max_models=max_models,
|
||||
)
|
||||
|
||||
# --- Deduplicate: remove models from aggregators that overlap with
|
||||
# user-defined providers. When a local proxy (e.g. litellm-proxy)
|
||||
# serves a model whose name also appears in an aggregator's curated
|
||||
# catalog, the picker would show the model under both providers.
|
||||
# Selecting it from the aggregator row sets model.provider to the
|
||||
# aggregator (e.g. openrouter) instead of the user's proxy — silently
|
||||
# breaking the call. Filtering at the payload level keeps the
|
||||
# aggregator rows honest: they only show models the user can't get
|
||||
# from a more-specific provider. (#45954)
|
||||
try:
|
||||
from hermes_cli.providers import is_aggregator as _is_aggregator
|
||||
except Exception:
|
||||
_is_aggregator = None # type: ignore[assignment]
|
||||
|
||||
if _is_aggregator is not None:
|
||||
user_models: set[str] = set()
|
||||
for row in rows:
|
||||
if row.get("is_user_defined"):
|
||||
user_models.update(m.lower() for m in (row.get("models") or []))
|
||||
if user_models:
|
||||
for row in rows:
|
||||
slug = row.get("slug", "")
|
||||
if not _is_aggregator(slug):
|
||||
continue
|
||||
original = row.get("models") or []
|
||||
filtered = [m for m in original if m.lower() not in user_models]
|
||||
if len(filtered) < len(original):
|
||||
row["models"] = filtered
|
||||
row["total_models"] = len(filtered)
|
||||
|
||||
if include_unconfigured:
|
||||
rows = list(rows) + _append_unconfigured_rows(rows, ctx)
|
||||
if picker_hints:
|
||||
|
||||
Reference in New Issue
Block a user