mirror of
https://github.com/Routstr/routstr-core.git
synced 2026-10-05 20:28:23 +00:00
fix: send placeholder key to litellm for keyless upstreams on /v1/messages
LiteLLM treats a blank api_key as missing and falls back to OPENAI_API_KEY, so /v1/messages against a keyless OpenAI-compatible upstream failed with "The api_key client option must be set", while /v1/chat/completions on the same upstream worked (it omits auth). LiteLLM has no option to skip the key, so pass a placeholder instead.
This commit is contained in:
@@ -36,6 +36,12 @@ from .reasoning_effort import adapt_messages_body_for_litellm
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
# Sent in place of a blank upstream key. LiteLLM treats ``""`` as missing and
|
||||
# falls back to the provider's env var (e.g. ``OPENAI_API_KEY``), failing with
|
||||
# an AuthenticationError for keyless upstreams such as self-hosted
|
||||
# OpenAI-compatible servers, which the chat path reaches without auth.
|
||||
KEYLESS_UPSTREAM_API_KEY = "no-key"
|
||||
|
||||
# Anthropic-Messages-only fields that don't translate to OpenAI
|
||||
# Chat Completions. ``litellm.drop_params`` only filters *known*
|
||||
# unsupported params; these newer/extension fields get passed through
|
||||
@@ -519,7 +525,7 @@ async def dispatch_anthropic_messages(
|
||||
kwargs: dict = {
|
||||
"model": litellm_model,
|
||||
"api_base": base_url,
|
||||
"api_key": api_key,
|
||||
"api_key": api_key or KEYLESS_UPSTREAM_API_KEY,
|
||||
"stream": upstream_stream,
|
||||
**body,
|
||||
}
|
||||
|
||||
@@ -1755,3 +1755,31 @@ async def test_x_cashu_zero_value_rejected_not_forwarded(
|
||||
assert body["error"]["code"] == "cashu_token_zero_value"
|
||||
# Spent-to-zero token must not be echoed back for retry.
|
||||
assert "X-Cashu" not in response.headers
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_dispatch_passes_placeholder_key_for_keyless_upstream() -> None:
|
||||
"""A blank upstream key must not reach litellm, which would fall back to
|
||||
OPENAI_API_KEY and fail with an AuthenticationError."""
|
||||
provider = BaseUpstreamProvider(base_url="http://localhost:8000/v1", api_key="")
|
||||
captured_kwargs: dict[str, Any] = {}
|
||||
|
||||
async def fake_acreate(**kwargs: Any) -> AsyncIterator[dict]:
|
||||
captured_kwargs.update(kwargs)
|
||||
|
||||
async def no_events() -> AsyncIterator[dict]:
|
||||
return
|
||||
yield
|
||||
|
||||
return no_events()
|
||||
|
||||
with patch(
|
||||
"litellm.anthropic.messages.acreate",
|
||||
new=AsyncMock(side_effect=fake_acreate),
|
||||
):
|
||||
await provider._dispatch_anthropic_messages(
|
||||
request_body=_anthropic_request_body(stream=True),
|
||||
model_obj=_make_model(),
|
||||
)
|
||||
|
||||
assert captured_kwargs["api_key"] == "no-key"
|
||||
|
||||
Reference in New Issue
Block a user