From 7f3de6ea3e41c7d43ccf43261b46b1c70ee194f9 Mon Sep 17 00:00:00 2001 From: Xubin Ren <52506698+Re-bin@users.noreply.github.com> Date: Sun, 26 Jul 2026 15:54:31 +0800 Subject: [PATCH] fix(providers): use canonical OpenRouter app URL --- nanobot/providers/image_generation.py | 8 ++------ nanobot/providers/openai_compat_provider.py | 8 ++------ nanobot/providers/openrouter_attribution.py | 7 +++++++ tests/providers/test_image_generation.py | 3 +++ tests/providers/test_litellm_kwargs.py | 2 +- 5 files changed, 15 insertions(+), 13 deletions(-) create mode 100644 nanobot/providers/openrouter_attribution.py diff --git a/nanobot/providers/image_generation.py b/nanobot/providers/image_generation.py index 94b9a75e9..4ee03b3db 100644 --- a/nanobot/providers/image_generation.py +++ b/nanobot/providers/image_generation.py @@ -14,14 +14,10 @@ from typing import Any import httpx from loguru import logger +from nanobot.providers.openrouter_attribution import OPENROUTER_ATTRIBUTION_HEADERS from nanobot.providers.registry import find_by_name from nanobot.utils.helpers import detect_image_mime -_OPENROUTER_ATTRIBUTION_HEADERS = { - "HTTP-Referer": "https://github.com/HKUDS/nanobot", - "X-OpenRouter-Title": "nanobot", - "X-OpenRouter-Categories": "cli-agent,personal-agent", -} _DEFAULT_TIMEOUT_S = 120.0 _AIHUBMIX_TIMEOUT_S = 300.0 _AIHUBMIX_ASPECT_RATIO_SIZES = { @@ -305,7 +301,7 @@ class OpenRouterImageGenerationClient(ImageGenerationProvider): headers = { "Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json", - **_OPENROUTER_ATTRIBUTION_HEADERS, + **OPENROUTER_ATTRIBUTION_HEADERS, **self.extra_headers, } url = f"{self.api_base}/chat/completions" diff --git a/nanobot/providers/openai_compat_provider.py b/nanobot/providers/openai_compat_provider.py index c8bad3c86..4bef89a19 100644 --- a/nanobot/providers/openai_compat_provider.py +++ b/nanobot/providers/openai_compat_provider.py @@ -35,6 +35,7 @@ from nanobot.providers.openai_responses import ( convert_tools, parse_response_output, ) +from nanobot.providers.openrouter_attribution import OPENROUTER_ATTRIBUTION_HEADERS if TYPE_CHECKING: from openai import AsyncOpenAI as AsyncOpenAIType @@ -54,11 +55,6 @@ _ALNUM = string.ascii_letters + string.digits _STANDARD_TC_KEYS = frozenset({"id", "type", "index", "function"}) _STANDARD_FN_KEYS = frozenset({"name", "arguments"}) -_DEFAULT_OPENROUTER_HEADERS = { - "HTTP-Referer": "https://github.com/HKUDS/nanobot", - "X-OpenRouter-Title": "nanobot", - "X-OpenRouter-Categories": "cli-agent,personal-agent", -} _KIMI_K3_MODEL = "kimi-k3" _KIMI_THINKING_MODELS: frozenset[str] = frozenset({ "kimi-k2.5", @@ -450,7 +446,7 @@ class OpenAICompatProvider(LLMProvider): self._effective_base = effective_base self._default_headers = {"x-session-affinity": uuid.uuid4().hex} if _uses_openrouter_attribution(spec, effective_base): - self._default_headers.update(_DEFAULT_OPENROUTER_HEADERS) + self._default_headers.update(OPENROUTER_ATTRIBUTION_HEADERS) if extra_headers: self._default_headers.update(extra_headers) self._api_key_for_client = api_key or "no-key" diff --git a/nanobot/providers/openrouter_attribution.py b/nanobot/providers/openrouter_attribution.py new file mode 100644 index 000000000..94ccccead --- /dev/null +++ b/nanobot/providers/openrouter_attribution.py @@ -0,0 +1,7 @@ +"""Shared OpenRouter app attribution headers.""" + +OPENROUTER_ATTRIBUTION_HEADERS = { + "HTTP-Referer": "https://nanobot.wiki", + "X-OpenRouter-Title": "nanobot", + "X-OpenRouter-Categories": "cli-agent,personal-agent", +} diff --git a/tests/providers/test_image_generation.py b/tests/providers/test_image_generation.py index cbb0f99ad..54240ae2b 100644 --- a/tests/providers/test_image_generation.py +++ b/tests/providers/test_image_generation.py @@ -142,6 +142,9 @@ async def test_openrouter_image_generation_payload_and_response(tmp_path: Path) call = fake.calls[0] assert call["url"] == "https://openrouter.ai/api/v1/chat/completions" assert call["headers"]["Authorization"] == "Bearer sk-or-test" + assert call["headers"]["HTTP-Referer"] == "https://nanobot.wiki" + assert call["headers"]["X-OpenRouter-Title"] == "nanobot" + assert call["headers"]["X-OpenRouter-Categories"] == "cli-agent,personal-agent" assert call["headers"]["X-Test"] == "1" body = call["json"] assert body["modalities"] == ["image", "text"] diff --git a/tests/providers/test_litellm_kwargs.py b/tests/providers/test_litellm_kwargs.py index c62258f21..b9c333ff6 100644 --- a/tests/providers/test_litellm_kwargs.py +++ b/tests/providers/test_litellm_kwargs.py @@ -485,7 +485,7 @@ async def test_openrouter_sets_default_attribution_headers() -> None: await provider._ensure_client() headers = mock_client_cls.call_args.kwargs["default_headers"] - assert headers["HTTP-Referer"] == "https://github.com/HKUDS/nanobot" + assert headers["HTTP-Referer"] == "https://nanobot.wiki" assert headers["X-OpenRouter-Title"] == "nanobot" assert headers["X-OpenRouter-Categories"] == "cli-agent,personal-agent" assert "x-session-affinity" in headers