From 1d72a45be42a917c1288bf9e2f7945ebc5c228fe Mon Sep 17 00:00:00 2001 From: mateo Date: Fri, 23 Oct 2026 23:38:14 +0000 Subject: [PATCH] fix(vllm): list hosted_vllm/* models without an api key Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/llms/vllm/common_utils.py | 15 ++++--- tests/unit/llms/vllm/test_common_utils.py | 52 +++++++++++++++++++++++ 2 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 tests/unit/llms/vllm/test_common_utils.py diff --git a/litellm/llms/vllm/common_utils.py b/litellm/llms/vllm/common_utils.py index 6484cdc88e3..022e7902e4d 100644 --- a/litellm/llms/vllm/common_utils.py +++ b/litellm/llms/vllm/common_utils.py @@ -1,3 +1,4 @@ +from types import MappingProxyType from typing import Final import httpx @@ -45,16 +46,17 @@ class VLLMModelInfo(BaseLLMModelInfo): @staticmethod def get_api_base(api_base: str | None = None) -> str | None: - api_base = api_base or get_secret_str("VLLM_API_BASE") + api_base = api_base or get_secret_str("HOSTED_VLLM_API_BASE") or get_secret_str("VLLM_API_BASE") if api_base is None: raise ValueError( - "VLLM_API_BASE is not set. Please set the environment variable, to use VLLM's pass-through - `{LITELLM_API_BASE}/vllm/{endpoint}`." + "HOSTED_VLLM_API_BASE or VLLM_API_BASE is not set. Please set an environment variable to use " + "VLLM's pass-through - `{LITELLM_API_BASE}/vllm/{endpoint}`." ) return api_base @staticmethod def get_api_key(api_key: str | None = None) -> str | None: - return None + return api_key or get_secret_str("HOSTED_VLLM_API_KEY") @staticmethod def get_base_model(model: str) -> str | None: @@ -64,14 +66,17 @@ class VLLMModelInfo(BaseLLMModelInfo): api_base = VLLMModelInfo.get_api_base(api_base) api_key = VLLMModelInfo.get_api_key(api_key) endpoint: Final = "/v1/models" - if api_base is None or api_key is None: + if api_base is None: raise ValueError( - "VLLM_API_BASE or VLLM_API_KEY is not set. Please set the environment variable, to query VLLM's `/models` endpoint." + "HOSTED_VLLM_API_BASE or VLLM_API_BASE is not set. Please set an environment variable to query " + "VLLM's `/models` endpoint." ) url: Final = add_path_to_api_base(api_base, endpoint) + headers: Final = MappingProxyType({"Authorization": f"Bearer {api_key}"}) if api_key is not None else None response: Final = litellm.module_level_client.get( url=url, + headers=headers, ) response.raise_for_status() diff --git a/tests/unit/llms/vllm/test_common_utils.py b/tests/unit/llms/vllm/test_common_utils.py new file mode 100644 index 00000000000..e34600d838e --- /dev/null +++ b/tests/unit/llms/vllm/test_common_utils.py @@ -0,0 +1,52 @@ +import httpx +import pytest +import respx + +from litellm.llms.vllm.common_utils import VLLMModelInfo + +MODELS_URL = "http://vllm.example/v1/models" +MODEL_RESPONSE = {"data": [{"id": "Qwen/Qwen3-8B"}]} + + +def test_get_models_without_api_key_sends_no_authorization_header(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.delenv("HOSTED_VLLM_API_KEY", raising=False) + + with respx.mock: + route = respx.get(MODELS_URL).mock(return_value=httpx.Response(200, json=MODEL_RESPONSE)) + models = VLLMModelInfo().get_models(api_base="http://vllm.example/v1") + + assert models == ["Qwen/Qwen3-8B"] + assert "authorization" not in route.calls[0].request.headers + + +def test_get_models_sends_api_key_as_bearer_token() -> None: + with respx.mock: + route = respx.get(MODELS_URL).mock(return_value=httpx.Response(200, json=MODEL_RESPONSE)) + models = VLLMModelInfo().get_models( + api_key="vllm-test-key", + api_base="http://vllm.example/v1", + ) + + assert models == ["Qwen/Qwen3-8B"] + assert route.calls[0].request.headers["authorization"] == "Bearer vllm-test-key" + + +def test_get_models_requires_api_base(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.delenv("HOSTED_VLLM_API_BASE", raising=False) + monkeypatch.delenv("VLLM_API_BASE", raising=False) + + with pytest.raises(ValueError, match="HOSTED_VLLM_API_BASE"): + VLLMModelInfo().get_models(api_key="vllm-test-key") + + +def test_get_api_key_falls_back_to_hosted_vllm_environment_variable(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("HOSTED_VLLM_API_KEY", "hosted-vllm-test-key") + + assert VLLMModelInfo.get_api_key() == "hosted-vllm-test-key" + + +def test_get_api_base_prefers_hosted_vllm_environment_variable(monkeypatch: pytest.MonkeyPatch) -> None: + monkeypatch.setenv("HOSTED_VLLM_API_BASE", "http://hosted-vllm.example/v1") + monkeypatch.setenv("VLLM_API_BASE", "http://vllm.example/v1") + + assert VLLMModelInfo.get_api_base() == "http://hosted-vllm.example/v1"