fix: ignore Open WebUI-owned keys in upstream model listings

Models from an OpenAI-compatible connection are merged with the upstream response spread in verbatim, so a gateway can set keys Open WebUI assigns itself. A gateway sending `preset` makes the admin model list treat a model that has no workspace entry as a preset, so clicking Edit opens the workspace model editor on an id that does not exist there and the request 404s. `pipe`, `arena`, `action_ids` and `filter_ids` do more damage: they route chat completions to a local function that is not there, let access be decided by upstream-supplied grants, and attach local functions to a remote model.

Upstream entries are now merged without those keys. Every other field, including ones Open WebUI knows nothing about, still passes through untouched, and models that Open WebUI itself marks as presets are unaffected.

One consequence worth calling out: when a connection points at another Open WebUI instance, that instance's `info` block is no longer inherited, so those models lose the remote description, icon and capability flags. Inheriting another instance's database-shaped state, down to its `user_id` and access grants, is what makes this whole class of bug possible, so it goes with the rest.

Fixes #29629
This commit is contained in:
Classic298 2026-09-05 12:50:30 +02:00
parent 85b11a4f35
commit 95667c2e47

View file

@ -77,6 +77,7 @@ log = logging.getLogger(__name__)
_STRIP_PROXY_HEADERS = frozenset({'Content-Encoding', 'Content-Length', 'Transfer-Encoding'})
_MODEL_LIST_TIMEOUT = aiohttp.ClientTimeout(total=AIOHTTP_CLIENT_TIMEOUT_MODEL_LIST)
_UNSUPPORTED_OPENAI_MODEL_KEYWORDS = ('babbage', 'dall-e', 'davinci', 'embedding', 'tts', 'whisper')
_STRIP_MODEL_KEYS = frozenset({'action_ids', 'arena', 'filter_ids', 'info', 'pipe', 'preset'})
BASE_MODELS_CACHE_KEY = f'{REDIS_KEY_PREFIX}:models:base'
@ -85,6 +86,11 @@ 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 _clean_model_keys(model: dict) -> dict:
"""Return a copy of *model* without the keys Open WebUI assigns itself."""
return {k: v for k, v in model.items() if k not in _STRIP_MODEL_KEYS}
async def send_get_request(
request: Request = None,
url=None,
@ -835,7 +841,7 @@ async def get_all_models(request: Request, user: UserModel) -> dict[str, list]:
if model_id and model_id not in models:
provider = model.get('provider', '')
merged = {
**model,
**_clean_model_keys(model),
'name': model.get('name', model_id),
'owned_by': 'openai',
'openai': model,