mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(nadir): scope NADIR_API_KEY on endpoint-inferred calls
A call with no provider prefix and api_base set to the hosted Nadir API (e.g. model="bucket") was inferred as nadir by get_llm_provider's endpoint matching, which loaded NADIR_API_KEY unconditionally. With NADIR_API_BASE pointing at a self-hosted Nadir, that internal key was sent to the hosted API, bypassing the base scoping the explicit nadir branch and NadirDecisionsConfig.resolve_connection apply. The inference branch now loads the env key only when the configured base (NADIR_API_BASE, else the hosted default) is the hosted API. This covers both the chat and Decisions paths, which share the inference. Adds an asystemone integration test for both inferred cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
3f59c7b99a
commit
65f03bf7c0
3 changed files with 32 additions and 3 deletions
|
|
@ -315,8 +315,14 @@ def get_llm_provider(
|
|||
dynamic_api_key = get_secret_str("CEREBRAS_API_KEY")
|
||||
elif endpoint == NADIR_DEFAULT_API_BASE:
|
||||
custom_llm_provider = "nadir" # rebind-ok: mirrors sibling endpoint branches
|
||||
# NADIR_API_KEY belongs to NADIR_API_BASE, the same scoping as the explicit nadir branch:
|
||||
# it reaches the hosted API only when that is the configured base.
|
||||
dynamic_api_key = (
|
||||
get_secret_str("NADIR_API_KEY") if api_base.lower().startswith("https://") else None
|
||||
get_secret_str("NADIR_API_KEY")
|
||||
if api_base.lower().startswith("https://")
|
||||
and (get_secret_str("NADIR_API_BASE") or NADIR_DEFAULT_API_BASE).rstrip("/")
|
||||
== NADIR_DEFAULT_API_BASE
|
||||
else None
|
||||
)
|
||||
elif endpoint == "https://inference.baseten.co/v1":
|
||||
custom_llm_provider = "baseten"
|
||||
|
|
|
|||
|
|
@ -142,8 +142,9 @@ class NadirDecisionsConfig(BaseDecisionsConfig):
|
|||
"""Nadir as a Decisions provider: ``/v1/bucket`` answers a single simple/medium/complex choice question.
|
||||
|
||||
Nadir is a tier classifier, not a general judge, so any other question set is rejected before a call.
|
||||
``NADIR_API_KEY`` is only sent to ``NADIR_API_BASE`` or the hosted API, the same scoping as the ``nadir``
|
||||
chat provider; with no key the call is anonymous, which Nadir serves on a per-IP rate-limited tier.
|
||||
``NADIR_API_KEY`` is only sent to ``NADIR_API_BASE`` (the hosted API when unset), whether the provider is named
|
||||
or inferred from the base, the same scoping as the ``nadir`` chat provider; with no key the call is anonymous,
|
||||
which Nadir serves on a per-IP rate-limited tier.
|
||||
"""
|
||||
|
||||
path = "/v1/bucket"
|
||||
|
|
|
|||
|
|
@ -727,6 +727,28 @@ async def test_nadir_answers_a_tier_question_from_its_bucket_verdict_and_keeps_i
|
|||
assert "authorization" not in elsewhere.calls.last.request.headers
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_nadir_inferred_from_the_hosted_base_sends_only_a_hosted_key(
|
||||
monkeypatch: pytest.MonkeyPatch, respx_mock: respx.MockRouter
|
||||
) -> None:
|
||||
monkeypatch.setenv("NADIR_API_KEY", "ndr-env")
|
||||
verdict: Final = {"routing_tier": "simple", "confidence": 0.8}
|
||||
hosted: Final = respx_mock.post("https://api.getnadir.com/v1/bucket").respond(json=verdict)
|
||||
questions: Final = {"tier": {"type": "choice", "criteria": {"simple": None, "medium": None, "complex": None}}}
|
||||
|
||||
monkeypatch.delenv("NADIR_API_BASE", raising=False)
|
||||
_ = await litellm.asystemone(
|
||||
model="bucket", state="hi", questions=questions, api_base="https://api.getnadir.com/v1"
|
||||
)
|
||||
monkeypatch.setenv("NADIR_API_BASE", "https://nadir.internal/v1")
|
||||
_ = await litellm.asystemone(
|
||||
model="bucket", state="hi", questions=questions, api_base="https://api.getnadir.com/v1"
|
||||
)
|
||||
|
||||
assert hosted.calls[0].request.headers["authorization"] == "Bearer ndr-env"
|
||||
assert "authorization" not in hosted.calls[1].request.headers
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_nadir_refuses_a_question_it_cannot_answer_before_any_call(respx_mock: respx.MockRouter) -> None:
|
||||
upstream: Final = respx_mock.post("https://api.getnadir.com/v1/bucket")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue