mirror of
https://github.com/BerriAI/litellm.git
synced 2026-10-09 03:18:44 +00:00
fix(voyage): route rerank on the key it authenticates with
get_complete_url picked the rerank host from the environment while the auth header carried the request key, so an explicit MongoDB-issued key was posted to api.voyageai.com. validate_environment now hands the resolved key to the config instance and get_complete_url reads it back, so the host and the credential always come from one key. The config is built per request, so nothing carries over between them.
This commit is contained in:
parent
c53cf2c2b4
commit
fcd9a894d9
2 changed files with 67 additions and 4 deletions
|
|
@ -25,6 +25,16 @@ from ..embedding.transformation import VoyageError
|
|||
|
||||
|
||||
class VoyageRerankConfig(BaseRerankConfig):
|
||||
"""
|
||||
``validate_environment`` stores the credential it authenticates with so ``get_complete_url``
|
||||
can select the host that issued it. ``ProviderConfigManager.get_provider_rerank_config``
|
||||
builds this config per request, so that key never reaches another one.
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
super().__init__()
|
||||
self._api_key: str | None = None
|
||||
|
||||
def get_supported_cohere_rerank_params(self, model: str) -> list:
|
||||
return ["query", "documents", "top_n", "return_documents"]
|
||||
|
||||
|
|
@ -60,7 +70,7 @@ class VoyageRerankConfig(BaseRerankConfig):
|
|||
optional_params: dict | None = None,
|
||||
) -> str:
|
||||
if api_base is None:
|
||||
return f"{get_default_base_url()}/rerank"
|
||||
return f"{get_default_base_url(self._api_key)}/rerank"
|
||||
api_base = api_base.rstrip("/")
|
||||
if not api_base.endswith("/v1/rerank"):
|
||||
if api_base.endswith("/v1"):
|
||||
|
|
@ -144,6 +154,7 @@ class VoyageRerankConfig(BaseRerankConfig):
|
|||
resolved_api_key: Final = get_voyage_api_key(api_key)
|
||||
if resolved_api_key is None:
|
||||
raise ValueError("Voyage AI API key is required. Set via `api_key` parameter or `VOYAGE_API_KEY` env var.")
|
||||
self._api_key = resolved_api_key
|
||||
return {
|
||||
"Authorization": f"Bearer {resolved_api_key}",
|
||||
"content-type": "application/json",
|
||||
|
|
|
|||
|
|
@ -72,10 +72,61 @@ def test_explicit_api_base_overrides_key_routing(config, endpoint):
|
|||
assert url == f"https://gateway.internal/v1/{endpoint}"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("api_key, expected_host", [("al-key", MONGODB_API_BASE), ("pa-key", VOYAGE_API_BASE)])
|
||||
def test_rerank_routes_by_request_key_prefix(api_key, expected_host):
|
||||
config = VoyageRerankConfig()
|
||||
config.validate_environment({}, "rerank-2.5", api_key=api_key)
|
||||
|
||||
assert config.get_complete_url(None, "rerank-2.5") == f"{expected_host}/rerank"
|
||||
|
||||
|
||||
@pytest.mark.parametrize("api_key, expected_host", [("al-key", MONGODB_API_BASE), ("pa-key", VOYAGE_API_BASE)])
|
||||
def test_rerank_routes_by_env_key_prefix(monkeypatch, api_key, expected_host):
|
||||
monkeypatch.setenv("VOYAGE_API_KEY", api_key)
|
||||
assert VoyageRerankConfig().get_complete_url(None, "rerank-2.5") == f"{expected_host}/rerank"
|
||||
config = VoyageRerankConfig()
|
||||
config.validate_environment({}, "rerank-2.5")
|
||||
|
||||
assert config.get_complete_url(None, "rerank-2.5") == f"{expected_host}/rerank"
|
||||
|
||||
|
||||
def test_rerank_request_key_beats_env_key_for_routing(monkeypatch):
|
||||
"""A MongoDB key on the request must not be posted to the Voyage host the env key names"""
|
||||
monkeypatch.setenv("VOYAGE_API_KEY", "pa-from-env")
|
||||
config = VoyageRerankConfig()
|
||||
|
||||
headers = config.validate_environment({}, "rerank-2.5", api_key="al-on-request")
|
||||
|
||||
assert headers["Authorization"] == "Bearer al-on-request"
|
||||
assert config.get_complete_url(None, "rerank-2.5") == f"{MONGODB_API_BASE}/rerank"
|
||||
|
||||
|
||||
def test_rerank_config_is_built_per_request_so_keys_cannot_leak(monkeypatch):
|
||||
"""get_complete_url reads a key off the instance, so each request must get its own instance"""
|
||||
import litellm
|
||||
from litellm.types.utils import LlmProviders
|
||||
from litellm.utils import ProviderConfigManager
|
||||
|
||||
monkeypatch.delenv("VOYAGE_API_KEY", raising=False)
|
||||
first = ProviderConfigManager.get_provider_rerank_config(
|
||||
model="rerank-2.5", provider=LlmProviders.VOYAGE, api_base=None, present_version_params=[]
|
||||
)
|
||||
second = ProviderConfigManager.get_provider_rerank_config(
|
||||
model="rerank-2.5", provider=LlmProviders.VOYAGE, api_base=None, present_version_params=[]
|
||||
)
|
||||
assert isinstance(first, litellm.VoyageRerankConfig) and first is not second
|
||||
|
||||
first.validate_environment({}, "rerank-2.5", api_key="al-first-request")
|
||||
second.validate_environment({}, "rerank-2.5", api_key="pa-second-request")
|
||||
|
||||
assert first.get_complete_url(None, "rerank-2.5") == f"{MONGODB_API_BASE}/rerank"
|
||||
assert second.get_complete_url(None, "rerank-2.5") == f"{VOYAGE_API_BASE}/rerank"
|
||||
|
||||
|
||||
def test_rerank_falls_back_to_env_when_validate_environment_did_not_run(monkeypatch):
|
||||
"""A caller that skips validate_environment keeps the pre-existing env-only behaviour"""
|
||||
monkeypatch.setenv("VOYAGE_API_KEY", "al-from-env")
|
||||
|
||||
assert VoyageRerankConfig().get_complete_url(None, "rerank-2.5") == f"{MONGODB_API_BASE}/rerank"
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
|
|
@ -95,11 +146,12 @@ def test_auth_header_uses_the_key_the_url_was_routed_on(monkeypatch, config):
|
|||
|
||||
def test_rerank_auth_header_uses_the_key_the_url_was_routed_on(monkeypatch):
|
||||
monkeypatch.setenv("VOYAGE_AI_TOKEN", "al-from-env")
|
||||
config = VoyageRerankConfig()
|
||||
|
||||
headers = VoyageRerankConfig().validate_environment({}, "rerank-2.5")
|
||||
headers = config.validate_environment({}, "rerank-2.5")
|
||||
|
||||
assert headers["Authorization"] == "Bearer al-from-env"
|
||||
assert VoyageRerankConfig().get_complete_url(None, "rerank-2.5").startswith(MONGODB_API_BASE)
|
||||
assert config.get_complete_url(None, "rerank-2.5").startswith(MONGODB_API_BASE)
|
||||
|
||||
|
||||
def test_get_voyage_api_key_prefers_env_vars_in_documented_order(monkeypatch):
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue