fix(providers): require api_base before local provider wins on keyword match

Ollama's spec keeps "nemotron" as a keyword so bare `nemotron-3-nano`
auto-routes to a configured Ollama install (PR #1863). NVIDIA NIM was
later registered with the same "nemotron" keyword (commit 046d0831),
creating the only keyword collision in the registry.

In `_match_provider`, the keyword loop accepted any local provider on
`spec.is_local` alone — no api_base check. Models like
`nvidia/nemotron-3-super-120b-a12b` (intended for OpenRouter or NVIDIA
NIM) were therefore hijacked to http://localhost:11434/v1 even when the
user had never configured Ollama, causing silent connection errors at
runtime.

Add the same api_base gate the local-fallback loop already uses: a local
provider only wins by keyword when the user has actually set its
api_base. Preserves PR #1863's intent for users who configured Ollama;
fixes the silent hijack for everyone else.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
NearlCrews
2026-08-01 20:25:58 +08:00
committed by Xubin Ren
co-authored by Claude Opus 4.7
parent 4c387f6633
commit 5eb818e800
2 changed files with 45 additions and 0 deletions
+36
View File
@@ -1160,6 +1160,42 @@ def test_config_falls_back_to_vllm_when_ollama_not_configured():
assert config.get_api_base() == "http://localhost:8000"
def test_config_cloud_nemotron_is_not_hijacked_by_unconfigured_ollama():
"""`nvidia/nemotron-*` via a gateway must not route to Ollama when no
Ollama endpoint is configured. Ollama keeps "nemotron" in its keywords
for bare-model auto-routing (PR #1863), which previously hijacked
cloud-hosted nemotron variants and silently sent traffic to
http://localhost:11434/v1."""
config = Config.model_validate(
{
"agents": {
"defaults": {
"provider": "auto",
"model": "nvidia/nemotron-3-super-120b-a12b",
}
},
"providers": {"openrouter": {"apiKey": "sk-or-test"}},
}
)
assert config.get_provider_name() == "openrouter"
assert config.get_api_base() == "https://openrouter.ai/api/v1"
def test_config_bare_nemotron_still_auto_routes_to_configured_ollama():
"""Preserves PR #1863 intent: when the user has actually configured an
Ollama endpoint, a bare nemotron model still auto-routes there."""
config = Config.model_validate(
{
"agents": {"defaults": {"provider": "auto", "model": "nemotron-3-nano"}},
"providers": {"ollama": {"apiBase": "http://localhost:11434/v1"}},
}
)
assert config.get_provider_name() == "ollama"
assert config.get_api_base() == "http://localhost:11434/v1"
def test_openai_compat_provider_passes_model_through():
from nanobot.providers.openai_compat_provider import OpenAICompatProvider