mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-08-31 08:13:11 +03:00
fix(providers): preserve legacy OrcaRouter custom configs
This commit is contained in:
@@ -49,6 +49,30 @@ def _provider_extra_headers(
|
|||||||
return headers or None
|
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(
|
def _resolve_provider_setup(
|
||||||
config: Config,
|
config: Config,
|
||||||
*,
|
*,
|
||||||
@@ -61,7 +85,7 @@ def _resolve_provider_setup(
|
|||||||
p = config.get_provider(model, preset=preset)
|
p = config.get_provider(model, preset=preset)
|
||||||
if not provider_name:
|
if not provider_name:
|
||||||
raise ValueError(f"No provider is configured for model '{model}'.")
|
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 spec and p:
|
||||||
if not p.api_base:
|
if not p.api_base:
|
||||||
raise ValueError(f"Provider '{provider_name}' requires api_base in config.")
|
raise ValueError(f"Provider '{provider_name}' requires api_base in config.")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
|
||||||
from nanobot.config.schema import Config, ProvidersConfig
|
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.openai_compat_provider import OpenAICompatProvider
|
||||||
from nanobot.providers.registry import PROVIDERS, find_by_name
|
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"
|
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({
|
config = Config.model_validate({
|
||||||
"providers": {
|
"providers": {
|
||||||
"orcarouter": {
|
"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"
|
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:
|
def test_orcarouter_preserves_model_api_id() -> None:
|
||||||
spec = find_by_name("orcarouter")
|
spec = find_by_name("orcarouter")
|
||||||
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
|
with patch("nanobot.providers.openai_compat_provider.AsyncOpenAI"):
|
||||||
|
|||||||
Reference in New Issue
Block a user