fix(providers): preserve legacy OrcaRouter custom configs

This commit is contained in:
Xubin Ren
2026-08-16 00:26:51 +08:00
parent 656480546b
commit 8dc08853e4
2 changed files with 60 additions and 2 deletions
+25 -1
View File
@@ -49,6 +49,30 @@ def _provider_extra_headers(
return headers or None
def _provider_spec_for_config(
provider_name: str,
provider_config: ProviderConfig | None,
) -> ProviderSpec | None:
spec = find_by_name(provider_name)
if (
spec is not None
and spec.name == "orcarouter"
and provider_config is not None
and provider_config.api_base
and provider_config.api_base.rstrip("/").lower()
!= spec.default_api_base.rstrip("/").lower()
):
# Before OrcaRouter became a built-in provider, this name was valid for a
# dynamic custom provider. Preserve that provider's model-prefix behavior
# when an existing config points the name at a different endpoint.
return create_dynamic_spec(
provider_name,
display_name=provider_config.display_name or "",
thinking_style=provider_config.thinking_style or "",
)
return spec
def _resolve_provider_setup(
config: Config,
*,
@@ -61,7 +85,7 @@ def _resolve_provider_setup(
p = config.get_provider(model, preset=preset)
if not provider_name:
raise ValueError(f"No provider is configured for model '{model}'.")
spec = find_by_name(provider_name)
spec = _provider_spec_for_config(provider_name, p)
if not spec and p:
if not p.api_base:
raise ValueError(f"Provider '{provider_name}' requires api_base in config.")
+35 -1
View File
@@ -3,6 +3,7 @@
from unittest.mock import patch
from nanobot.config.schema import Config, ProvidersConfig
from nanobot.providers.factory import make_provider
from nanobot.providers.openai_compat_provider import OpenAICompatProvider
from nanobot.providers.registry import PROVIDERS, find_by_name
@@ -55,7 +56,7 @@ def test_orcarouter_forced_provider_uses_default_api_base() -> None:
assert config.get_api_base("deepseek/deepseek-chat") == "https://api.orcarouter.ai/v1"
def test_orcarouter_gateway_routes_unprefixed_models_when_configured() -> None:
def test_orcarouter_gateway_routes_auto_model_when_configured() -> None:
config = Config.model_validate({
"providers": {
"orcarouter": {
@@ -74,6 +75,39 @@ def test_orcarouter_gateway_routes_unprefixed_models_when_configured() -> None:
assert config.get_api_base("orcarouter/auto") == "https://api.orcarouter.ai/v1"
def test_legacy_custom_provider_named_orcarouter_keeps_prefix_stripping() -> None:
config = Config.model_validate({
"providers": {
"orcarouter": {
"apiKey": "legacy-test-key",
"apiBase": "https://legacy-gateway.example/v1",
},
},
"agents": {
"defaults": {
"model": "orcarouter/custom-model",
"provider": "orcarouter",
},
},
})
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
provider = make_provider(config)
assert isinstance(provider, OpenAICompatProvider)
assert provider.api_base == "https://legacy-gateway.example/v1"
kwargs = provider._build_kwargs(
messages=[{"role": "user", "content": "hi"}],
tools=None,
model="orcarouter/custom-model",
max_tokens=1024,
temperature=0.7,
reasoning_effort=None,
tool_choice=None,
)
assert kwargs["model"] == "custom-model"
def test_orcarouter_preserves_model_api_id() -> None:
spec = find_by_name("orcarouter")
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):