fix(model-metadata): resolve provider prefixes from live registry

This commit is contained in:
Teknium 2026-08-08 12:48:20 -07:00
parent 19e51d2cca
commit d143bf7a3b
2 changed files with 47 additions and 62 deletions

View File

@ -66,33 +66,19 @@ def _resolve_requests_verify() -> bool | str:
return val
return True
# Provider names that can appear as a "provider:" prefix before a model ID.
# Only these are stripped — Ollama-style "model:tag" colons (e.g. "qwen3.5:27b")
# are preserved so the full model name reaches cache lookups and server queries.
_PROVIDER_PREFIXES: frozenset[str] = frozenset({
"openrouter", "nous", "openai-codex", "copilot", "copilot-acp",
"gemini", "ollama-cloud", "zai", "kimi-coding", "kimi-coding-cn", "stepfun", "minimax", "minimax-oauth", "minimax-cn", "anthropic", "deepseek", "deepinfra",
"opencode-zen", "opencode-go", "ai-gateway", "kilocode", "alibaba", "novita",
"qwen-oauth",
"xiaomi",
"arcee",
"gmi",
"tencent-tokenhub",
"custom", "local",
# Common aliases
"google", "google-gemini", "google-ai-studio",
"glm", "z-ai", "z.ai", "zhipu", "github", "github-copilot",
"github-models", "kimi", "moonshot", "kimi-cn", "moonshot-cn", "claude", "deep-seek", "deep-infra",
"ollama",
"stepfun", "opencode", "zen", "go", "vercel", "kilo", "dashscope", "aliyun", "qwen",
"mimo", "xiaomi-mimo",
"tencent", "tokenhub", "tencent-cloud", "tencentmaas",
"arcee-ai", "arceeai",
"gmi-cloud", "gmicloud",
"xai", "x-ai", "x.ai", "grok",
"nvidia", "nim", "nvidia-nim", "nemotron",
"qwen-portal", "novita-ai", "novitaai",
})
# Compatibility snapshot for callers that inspect this private constant.
# Prefix routing below queries the registry live so later registrations work.
try:
from providers import list_providers as _list_providers
except Exception:
def _list_providers():
return []
_PROVIDER_PREFIXES: frozenset[str] = frozenset(
value.lower()
for profile in _list_providers()
for value in (profile.name, *profile.aliases)
)
_OLLAMA_TAG_PATTERN = re.compile(
@ -111,6 +97,9 @@ _TAILSCALE_CGNAT = ipaddress.IPv4Network("100.64.0.0/10")
def _strip_provider_prefix(model: str) -> str:
"""Strip a recognised provider prefix from a model string.
Provider names and aliases come from the provider-profile registry, so
bundled and user plugins are recognised without a core catalog update.
``"local:my-model"`` ``"my-model"``
``"qwen3.5:27b"`` ``"qwen3.5:27b"`` (unchanged not a provider prefix)
``"qwen:0.5b"`` ``"qwen:0.5b"`` (unchanged Ollama model:tag)
@ -120,7 +109,13 @@ def _strip_provider_prefix(model: str) -> str:
return model
prefix, suffix = model.split(":", 1)
prefix_lower = prefix.strip().lower()
if prefix_lower in _PROVIDER_PREFIXES:
try:
from providers import get_provider_profile
is_provider = get_provider_profile(prefix_lower) is not None
except Exception:
is_provider = False
if is_provider:
# Don't strip if suffix looks like an Ollama tag (e.g. "7b", "latest", "q4_0")
if _OLLAMA_TAG_PATTERN.match(suffix.strip()):
return model
@ -704,7 +699,6 @@ _URL_TO_PROVIDER: Dict[str, str] = {
# Auto-extend with hostnames derived from provider profiles.
# Any provider with a base_url not already in the map gets added automatically.
try:
from providers import list_providers as _list_providers
for _pp in _list_providers():
_host = _pp.get_hostname()
if _host and _host not in _URL_TO_PROVIDER:
@ -712,20 +706,6 @@ try:
except Exception:
pass
# Auto-extend _PROVIDER_PREFIXES the same way, so "provider:model" strings
# strip correctly for plugin providers (user plugins under
# $HERMES_HOME/plugins/model-providers/ included) without editing this file.
# The _OLLAMA_TAG_PATTERN guard in _strip_provider_prefix still protects
# Ollama-style "model:tag" strings from over-stripping.
try:
_plugin_prefixes: set[str] = set()
for _pp in _list_providers():
_plugin_prefixes.add(_pp.name.lower())
_plugin_prefixes.update(str(_a).lower() for _a in _pp.aliases)
_PROVIDER_PREFIXES = frozenset(_PROVIDER_PREFIXES | _plugin_prefixes)
except Exception:
pass
def _infer_provider_from_url(base_url: str) -> Optional[str]:
"""Infer the models.dev provider name from a base URL.

View File

@ -894,28 +894,33 @@ class TestStripProviderPrefix:
assert _strip_provider_prefix("http://example.com") == "http://example.com"
assert _strip_provider_prefix("https://example.com") == "https://example.com"
def test_registered_provider_names_and_aliases_are_prefixes(self):
"""Prefixes auto-extend from registered profiles, like _URL_TO_PROVIDER.
def test_registered_profile_name_and_alias_are_stripped(self, monkeypatch):
import providers
from providers import ProviderProfile
Bundled plugin providers (and user plugins under
$HERMES_HOME/plugins/model-providers/) must strip without a manual
entry in the static frozenset.
"""
from providers import list_providers
monkeypatch.setattr(providers, "_REGISTRY", {})
monkeypatch.setattr(providers, "_ALIASES", {})
monkeypatch.setattr(providers, "_PROVIDER_LIST_CACHE", None)
monkeypatch.setattr(providers, "_discovered", True)
providers.register_provider(
ProviderProfile(name="fake-provider", aliases=("fake-alias",))
)
from agent.model_metadata import _PROVIDER_PREFIXES
assert _strip_provider_prefix("fake-provider:org/model") == "org/model"
assert _strip_provider_prefix("fake-alias:org/model") == "org/model"
for profile in list_providers():
assert profile.name.lower() in _PROVIDER_PREFIXES, (
f"registered provider {profile.name!r} missing from prefixes"
)
for alias in profile.aliases:
assert str(alias).lower() in _PROVIDER_PREFIXES, (
f"alias {alias!r} of {profile.name!r} missing from prefixes"
)
# And a concrete strip using a bundled provider absent from the
# static set (fireworks ships as a plugin only).
assert _strip_provider_prefix("fireworks:some/model-v1") == "some/model-v1"
def test_bundled_plugin_provider_prefix_is_stripped(self):
assert _strip_provider_prefix("fireworks:accounts/fireworks/models/foo") == (
"accounts/fireworks/models/foo"
)
def test_unknown_provider_prefix_is_unchanged(self):
assert _strip_provider_prefix("not-a-provider:org/model") == (
"not-a-provider:org/model"
)
def test_ollama_model_tag_is_unchanged(self):
assert _strip_provider_prefix("qwen3.5:27b") == "qwen3.5:27b"
@patch("agent.model_metadata.fetch_model_metadata")
def test_ollama_model_tag_not_mangled_in_context_lookup(self, mock_fetch):