diff --git a/routstr/upstream/openrouter.py b/routstr/upstream/openrouter.py index 63995295..1caeaa5c 100644 --- a/routstr/upstream/openrouter.py +++ b/routstr/upstream/openrouter.py @@ -1,4 +1,3 @@ -import json from typing import TYPE_CHECKING import httpx @@ -19,38 +18,6 @@ class OpenRouterUpstreamProvider(BaseUpstreamProvider): supports_anthropic_messages = True litellm_provider_prefix = "openrouter/" - def prepare_request_body( - self, body: bytes | None, model_obj: Model - ) -> bytes | None: - """Set provider.require_parameters on tool-use requests. - - Without it OpenRouter can route a tool call to an endpoint that doesn't - support function calling and 404 with "No endpoints found that support - tool use". We leave a client-supplied value untouched. - """ - body = super().prepare_request_body(body, model_obj) - if not body: - return body - - try: - data = json.loads(body) - except json.JSONDecodeError: - return body - - if not isinstance(data, dict) or not data.get("tools"): - return body - - provider = data.get("provider") - if not isinstance(provider, dict): - provider = {} - - if "require_parameters" in provider: - return body - - provider["require_parameters"] = True - data["provider"] = provider - return json.dumps(data).encode() - def _apply_provider_field(self, response_json: object) -> None: """Stamp the ``provider`` field for OpenRouter responses. diff --git a/tests/unit/test_require_parameters.py b/tests/unit/test_require_parameters.py deleted file mode 100644 index 83c90652..00000000 --- a/tests/unit/test_require_parameters.py +++ /dev/null @@ -1,95 +0,0 @@ -import json -import os - -os.environ.setdefault("UPSTREAM_BASE_URL", "http://test") -os.environ.setdefault("UPSTREAM_API_KEY", "test") -os.environ.setdefault("LIGHTNING_ADDRESS", "test@stm.to") - -from routstr.upstream import GenericUpstreamProvider -from routstr.upstream.openrouter import OpenRouterUpstreamProvider - - -def _model(model_id: str = "openai/gpt-4o"): # type: ignore[no-untyped-def] - from routstr.payment.models import Architecture, Model, Pricing - - return Model( - id=model_id, - name=model_id, - created=0, - description="", - context_length=128000, - architecture=Architecture( - modality="text->text", - input_modalities=["text"], - output_modalities=["text"], - tokenizer="GPT", - instruct_type=None, - ), - pricing=Pricing(prompt=0.0, completion=0.0), - ) - - -def _tool_body() -> dict: - return { - "model": "openai/gpt-4o", - "messages": [{"role": "user", "content": "What's the weather?"}], - "tools": [ - { - "type": "function", - "function": {"name": "get_weather", "parameters": {}}, - } - ], - } - - -def _prepare(provider, body: dict) -> dict: # type: ignore[no-untyped-def] - out = provider.prepare_request_body(json.dumps(body).encode(), _model()) - assert out is not None - return json.loads(out) - - -def test_injects_require_parameters_for_tool_request() -> None: - data = _prepare(OpenRouterUpstreamProvider(api_key="test"), _tool_body()) - assert data["provider"]["require_parameters"] is True - - -def test_generic_provider_on_openrouter_url_is_left_alone() -> None: - # Only OpenRouterUpstreamProvider injects; a generic provider pointed at the - # same base URL doesn't. - provider = GenericUpstreamProvider(base_url="https://openrouter.ai/api/v1") - data = _prepare(provider, _tool_body()) - assert "provider" not in data - - -def test_no_injection_without_tools() -> None: - body = {"model": "openai/gpt-4o", "messages": [{"role": "user", "content": "hi"}]} - data = _prepare(OpenRouterUpstreamProvider(api_key="test"), body) - assert "provider" not in data - - -def test_empty_tools_list_does_not_inject() -> None: - body = _tool_body() - body["tools"] = [] - data = _prepare(OpenRouterUpstreamProvider(api_key="test"), body) - assert "provider" not in data - - -def test_direct_provider_does_not_inject() -> None: - provider = GenericUpstreamProvider(base_url="https://api.openai.com/v1") - data = _prepare(provider, _tool_body()) - assert "provider" not in data - - -def test_keeps_client_set_require_parameters() -> None: - body = _tool_body() - body["provider"] = {"require_parameters": False} - data = _prepare(OpenRouterUpstreamProvider(api_key="test"), body) - assert data["provider"]["require_parameters"] is False - - -def test_preserves_other_provider_fields() -> None: - body = _tool_body() - body["provider"] = {"order": ["openai", "azure"]} - data = _prepare(OpenRouterUpstreamProvider(api_key="test"), body) - assert data["provider"]["order"] == ["openai", "azure"] - assert data["provider"]["require_parameters"] is True