fix(profiles): resolve @provider:model through the shared parser (#7183)

_split_webui_provider_model_value() and _strip_webui_provider_prefix()
split provider-qualified model values at the last colon. That amputates
any model name carrying its own tag: @ollama:qwen3.8:27b-mtp-q8_0
resolved to model 27b-mtp-q8_0 with provider ollama:qwen3.8, and the
truncated name was sent upstream, which 404'd. The splitter also cannot
distinguish a tagged model from a multi-segment custom provider ID, so
@custom:mykey:model-a:free was affected the same way.

Both sites now delegate to config._parse_provider_qualified_model_id(),
the grammar routes.py and the gateway adopted in #6723. The import is
function-local, matching the existing api.config imports in this module.

_split_webui_provider_model_value() persists its result into profile
config, so the mangled name outlived the session that produced it.

Fixes #7182.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Co-authored-by: nesquena-hermes <nesquena+hermes@gmail.com>
This commit is contained in:
authored and GitHub committed 2026-08-21 06:45:52 +00:00
1 parent c54d3faca5
commit 05ab4173cf
2 files changed
+141 -5

No files matched your search

+26 -5
View File
@@ -2393,20 +2393,41 @@ def _clean_profile_config_value(value: Optional[str], field: str) -> Optional[st
def _split_webui_provider_model_value(default_model: Optional[str], model_provider: Optional[str]) -> tuple[Optional[str], Optional[str]]:
"""Normalize WebUI-internal @provider:model picker values for config.yaml."""
"""Normalize WebUI-internal @provider:model picker values for config.yaml.
Parsing is delegated to ``config._parse_provider_qualified_model_id()`` so
this agrees with the grammar every other call site uses (#6722, #6723). A
positional ``rsplit(":", 1)`` cannot tell a colon-tagged model
(``@ollama:qwen3.8:27b-mtp-q8_0``) from a multi-segment custom provider ID
(``@custom:backup:model-a``); it truncated the model name and persisted the
fragment into profile config, which the provider API then 404'd on (#7182).
"""
model = _clean_profile_config_value(default_model, "default_model")
provider = _clean_profile_config_value(model_provider, "model_provider")
if model and model.startswith("@") and ":" in model:
provider_part, model_part = model[1:].rsplit(":", 1)
provider = provider or _clean_profile_config_value(provider_part, "model_provider")
model = _clean_profile_config_value(model_part, "default_model")
from api.config import _parse_provider_qualified_model_id
parsed = _parse_provider_qualified_model_id(model)
if parsed:
model_part, provider_part = parsed
provider = provider or _clean_profile_config_value(provider_part, "model_provider")
model = _clean_profile_config_value(model_part, "default_model")
return model, provider
def _strip_webui_provider_prefix(model_id: object) -> str:
"""Return the bare model name from a WebUI ``@provider:model`` value.
Uses the same shared grammar as ``_split_webui_provider_model_value()`` so a
tagged model name survives the round trip (#7182).
"""
value = str(model_id or "").strip()
if value.startswith("@") and ":" in value:
return value.rsplit(":", 1)[1]
from api.config import _parse_provider_qualified_model_id
parsed = _parse_provider_qualified_model_id(value)
if parsed:
return str(parsed[0] or "").strip()
return value