mirror of
https://github.com/open-webui/open-webui.git
synced 2026-11-11 08:57:17 +00:00
fix: exclude non-chat models from OpenAI-compatible gateway catalogs
Gateways that front many providers (LiteLLM, OpenRouter-style aggregators, and others) return their entire catalog from `/models`, including embedding, image, video, rerank and audio models. Open WebUI listed all of them as chat models, so the model picker filled up with entries that fail as soon as they are selected. These gateways already mark each entry with the OpenAI-style `supported_operations` / `supported_endpoints` hints. Honour them when building the model list, and pick the required operation based on the connection's `api_type` so Responses-API connections list Responses models. Providers that do not advertise these fields are treated as chat capable, so plain OpenAI, Ollama and vLLM connections are unaffected. Connections with a manually configured `model_ids` list are left untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
2dadc5435a
commit
c1b227cf81
1 changed files with 51 additions and 0 deletions
|
|
@ -86,6 +86,34 @@ def _clean_proxy_headers(raw_headers) -> dict:
|
|||
return {k: v for k, v in raw_headers.items() if k not in _STRIP_PROXY_HEADERS}
|
||||
|
||||
|
||||
def supports_text_generation(model: dict, api_type: str | None = None) -> bool:
|
||||
"""Whether *model* can serve the text generation endpoint this connection uses.
|
||||
|
||||
Gateways that front many providers return their whole catalog from
|
||||
``/models`` - embedding, image, video, rerank and audio models included -
|
||||
and mark each entry with the OpenAI-style ``supported_operations`` /
|
||||
``supported_endpoints`` hints. Without this check every one of those
|
||||
non-chat models shows up in the chat model picker. Providers that
|
||||
advertise nothing are assumed to be chat capable, which keeps plain
|
||||
OpenAI / Ollama / vLLM behaviour unchanged.
|
||||
"""
|
||||
if not isinstance(model, dict):
|
||||
return True
|
||||
|
||||
operation = 'RESPONSES' if api_type == 'responses' else 'CHAT_COMPLETIONS'
|
||||
|
||||
operations = model.get('supported_operations')
|
||||
if isinstance(operations, list) and operations:
|
||||
return operation in operations
|
||||
|
||||
endpoints = model.get('supported_endpoints')
|
||||
if isinstance(endpoints, list) and endpoints:
|
||||
endpoint = '/responses' if api_type == 'responses' else '/chat/completions'
|
||||
return any(isinstance(e, str) and e.endswith(endpoint) for e in endpoints)
|
||||
|
||||
return True
|
||||
|
||||
|
||||
async def send_get_request(
|
||||
request: Request = None,
|
||||
url=None,
|
||||
|
|
@ -596,6 +624,20 @@ async def get_all_models_responses(request: Request, user: UserModel) -> list:
|
|||
# Catch non-list responses
|
||||
model_list = []
|
||||
|
||||
if not api_config.get('model_ids'):
|
||||
# Manually listed model ids are taken at face value; a fetched
|
||||
# catalog gets narrowed down to the models this connection can
|
||||
# actually chat with.
|
||||
api_type = api_config.get('api_type')
|
||||
filtered = [model for model in model_list if supports_text_generation(model, api_type)]
|
||||
|
||||
if len(filtered) != len(model_list):
|
||||
model_list = filtered
|
||||
if isinstance(response, list):
|
||||
responses[idx] = model_list
|
||||
else:
|
||||
response['data'] = model_list
|
||||
|
||||
for model in model_list:
|
||||
# Remove name key if its value is None #16689
|
||||
if 'name' in model and model['name'] is None:
|
||||
|
|
@ -773,6 +815,15 @@ async def get_models(request: Request, url_idx: int | None = None, user=Depends(
|
|||
for model in response_data.get('data', [])
|
||||
if not any(name in model['id'] for name in _UNSUPPORTED_OPENAI_MODEL_KEYWORDS)
|
||||
]
|
||||
elif isinstance(response_data, dict) and isinstance(response_data.get('data'), list):
|
||||
# Keep the model id picker in sync with what this
|
||||
# connection will actually serve as chat models.
|
||||
api_type = api_config.get('api_type')
|
||||
response_data['data'] = [
|
||||
model
|
||||
for model in response_data['data']
|
||||
if isinstance(model, dict) and supports_text_generation(model, api_type)
|
||||
]
|
||||
|
||||
models = response_data
|
||||
except aiohttp.ClientError as e:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue