fix(model-metadata): resolve provider prefixes from live registry
This commit is contained in:
parent
19e51d2cca
commit
d143bf7a3b
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
Loading…
Reference in New Issue