mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-14 09:03:16 +00:00
fix(proxy): keep a name the ChatGPT account lists on the subscription despite a saved alias
This commit is contained in:
parent
6680a8dbc4
commit
5123c3100a
3 changed files with 65 additions and 10 deletions
|
|
@ -344,6 +344,11 @@ async def _resolve_router_settings_model_group_alias(
|
|||
target: Final = resolve_model_group_alias(settings.get("model_group_alias"), requested)
|
||||
if target is None or target == requested:
|
||||
return
|
||||
if request_dispatched_to_provider_pass_through(request):
|
||||
from litellm.proxy.pass_through_endpoints.codex_passthrough_endpoints import native_turn_serves_through_litellm
|
||||
|
||||
if not await native_turn_serves_through_litellm(requested, llm_router, request, valid_token):
|
||||
return
|
||||
verbose_proxy_logger.debug(
|
||||
"router_settings.model_group_alias resolved %s -> %s before auth",
|
||||
requested.replace("\r", "").replace("\n", ""),
|
||||
|
|
|
|||
|
|
@ -276,6 +276,32 @@ async def _serves_through_litellm(
|
|||
return account_slugs is not None and model not in account_slugs
|
||||
|
||||
|
||||
def _gateway_token(request: Request) -> str:
|
||||
gateway_parts: Final = request.headers.get("x-litellm-api-key", "").split()
|
||||
return (
|
||||
gateway_parts[-1]
|
||||
if len(gateway_parts) == 1 or (len(gateway_parts) == 2 and gateway_parts[0].lower() == "bearer")
|
||||
else ""
|
||||
)
|
||||
|
||||
|
||||
def _forwarded_headers(request: Request) -> Mapping[str, str]:
|
||||
return MappingProxyType({name: value for name, value in request.headers.items() if name in _HEADERS})
|
||||
|
||||
|
||||
async def native_turn_serves_through_litellm(
|
||||
model: str, llm_router: "Router", request: Request, user_api_key_dict: UserAPIKeyAuth
|
||||
) -> bool:
|
||||
return await _serves_through_litellm(
|
||||
model,
|
||||
llm_router,
|
||||
user_api_key_dict,
|
||||
_models_etag_caller(user_api_key_dict, _gateway_token(request)),
|
||||
_forwarded_headers(request),
|
||||
codex_shared_cache(),
|
||||
)
|
||||
|
||||
|
||||
def _json_object(value: object) -> Mapping[str, object]:
|
||||
try:
|
||||
return _JSON_OBJECT.validate_python(value)
|
||||
|
|
@ -672,13 +698,7 @@ async def codex_passthrough_route(
|
|||
|
||||
authorization: Final = request.headers.get("authorization", "")
|
||||
scheme, _, token = authorization.partition(" ")
|
||||
gateway_key: Final = request.headers.get("x-litellm-api-key", "")
|
||||
gateway_parts: Final = gateway_key.split()
|
||||
gateway_token: Final = (
|
||||
gateway_parts[-1]
|
||||
if len(gateway_parts) == 1 or (len(gateway_parts) == 2 and gateway_parts[0].lower() == "bearer")
|
||||
else ""
|
||||
)
|
||||
gateway_token: Final = _gateway_token(request)
|
||||
if scheme.lower() != "bearer" or not token.strip() or not gateway_token:
|
||||
raise HTTPException(
|
||||
status_code=401,
|
||||
|
|
@ -687,7 +707,7 @@ async def codex_passthrough_route(
|
|||
if hmac.compare_digest(token.strip().encode(), gateway_token.encode()):
|
||||
raise HTTPException(status_code=401, detail="ChatGPT and LiteLLM credentials must be separate")
|
||||
|
||||
headers: Final = MappingProxyType({name: value for name, value in request.headers.items() if name in _HEADERS})
|
||||
headers: Final = _forwarded_headers(request)
|
||||
caller: Final = _models_etag_caller(user_api_key_dict, gateway_token)
|
||||
if endpoint == "models":
|
||||
return await _catalog(request, user_api_key_dict, caller, headers, cache)
|
||||
|
|
|
|||
|
|
@ -39,8 +39,7 @@ _HEADERS: Final = {"authorization": f"Bearer {_TOKEN}", "x-litellm-api-key": MAS
|
|||
@pytest.fixture
|
||||
def client(monkeypatch: pytest.MonkeyPatch, httpx_transport: None) -> Iterator[TestClient]:
|
||||
monkeypatch.setattr(proxy_server, "master_key", MASTER_KEY)
|
||||
shared_cache: Final = DualCache()
|
||||
monkeypatch.setitem(proxy_server.app.dependency_overrides, codex_shared_cache, lambda: shared_cache)
|
||||
monkeypatch.setattr(proxy_server.proxy_logging_obj.internal_usage_cache, "dual_cache", DualCache())
|
||||
yield TestClient(proxy_server.app)
|
||||
|
||||
|
||||
|
|
@ -760,6 +759,37 @@ def test_native_route_keeps_a_chatgpt_turn_on_the_subscription_despite_a_saved_a
|
|||
assert [json.loads(call.request.content)["model"] for call in chatgpt.calls] == [_BUNDLED_SLUG]
|
||||
|
||||
|
||||
def test_native_route_keeps_a_name_the_account_lists_on_the_subscription_despite_a_saved_alias(
|
||||
client: TestClient, respx_mock: respx.MockRouter, monkeypatch: pytest.MonkeyPatch
|
||||
) -> None:
|
||||
monkeypatch.setattr(proxy_server, "prisma_client", "test-database")
|
||||
monkeypatch.setattr(
|
||||
proxy_server, "llm_router", Router(model_list=[_open_weights("gpt-reserve"), _open_weights("group-b")])
|
||||
)
|
||||
key: Final = "sk-test-alias-on-a-name-the-account-lists"
|
||||
proxy_server.user_api_key_cache.set_cache(
|
||||
key=hash_token(key),
|
||||
value=UserAPIKeyAuth(
|
||||
token=hash_token(key),
|
||||
models=["gpt-reserve", "group-b"],
|
||||
router_settings={"model_group_alias": {"gpt-reserve": "group-b"}},
|
||||
model_max_budget={"group-b": {"max_budget": 0.0, "budget_duration": "1d"}},
|
||||
),
|
||||
)
|
||||
catalog: Final = respx_mock.get(f"{_BASE}/models").respond(json={"models": [{"slug": "gpt-reserve"}]})
|
||||
provider: Final = _open_weights_provider(respx_mock)
|
||||
chatgpt: Final = _chatgpt_responses(respx_mock)
|
||||
response: Final = client.post(
|
||||
"/backend-api/codex/responses",
|
||||
json={"model": "gpt-reserve", "input": "Hello", "stream": True},
|
||||
headers={**_ACCOUNT_HEADERS, "x-litellm-api-key": key},
|
||||
)
|
||||
assert response.status_code == 200, response.text
|
||||
assert not provider.called
|
||||
assert [json.loads(call.request.content)["model"] for call in chatgpt.calls] == ["gpt-reserve"]
|
||||
assert catalog.call_count == 1
|
||||
|
||||
|
||||
def test_v1_request_for_a_gpt_name_still_reaches_the_catch_all_with_the_access_group_recipe(
|
||||
client: TestClient, respx_mock: respx.MockRouter, mixed_router: Router
|
||||
) -> None:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue