From 7bb1aeec4ed7db886c5be04f6603fadeef1582ec Mon Sep 17 00:00:00 2001 From: mateo Date: Tue, 3 Nov 2026 22:46:57 +0000 Subject: [PATCH] fix(proxy): honor the global OpenAI base override when picking the Codex catalog key Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/common_utils/codex_model_catalog.py | 14 ++++++++------ .../proxy/common_utils/test_codex_model_catalog.py | 10 ++++++++-- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/litellm/proxy/common_utils/codex_model_catalog.py b/litellm/proxy/common_utils/codex_model_catalog.py index 496110d36c0..18b2c471ff7 100644 --- a/litellm/proxy/common_utils/codex_model_catalog.py +++ b/litellm/proxy/common_utils/codex_model_catalog.py @@ -36,6 +36,7 @@ from urllib.parse import urlparse from packaging.version import Version from pydantic import ConfigDict, Field, StringConstraints, TypeAdapter, ValidationError +import litellm from litellm._logging import verbose_proxy_logger from litellm.litellm_core_utils.reasoning_effort_strength import nearest_declared_reasoning_effort from litellm.secret_managers.main import get_secret_str @@ -574,10 +575,13 @@ OPENAI_API_HOST: Final = "api.openai.com" def _is_openai_origin(api_base: object) -> bool: - """Whether a deployment's api_base is OpenAI itself, so its key may go to OpenAI's catalog endpoint.""" - if not api_base: + """Whether a deployment's OpenAI requests go to OpenAI itself, so its key may go to OpenAI's catalog + endpoint: its own api_base, else the global `litellm.api_base`, `OPENAI_BASE_URL` or `OPENAI_API_BASE` + override the OpenAI handler would apply, else OpenAI.""" + resolved: Final = api_base or litellm.api_base or os.getenv("OPENAI_BASE_URL") or os.getenv("OPENAI_API_BASE") + if not resolved: return True - return isinstance(api_base, str) and urlparse(api_base).hostname == OPENAI_API_HOST + return isinstance(resolved, str) and urlparse(resolved).hostname == OPENAI_API_HOST def _deployment_openai_key(deployment: DeploymentTypedDict) -> str | None: @@ -596,9 +600,7 @@ def _deployment_openai_key(deployment: DeploymentTypedDict) -> str | None: def _environment_openai_key() -> str | None: - if not _is_openai_origin(os.getenv("OPENAI_BASE_URL") or os.getenv("OPENAI_API_BASE")): - return None - return os.getenv("OPENAI_API_KEY") or None + return (os.getenv("OPENAI_API_KEY") or None) if _is_openai_origin(None) else None def codex_catalog_openai_key( diff --git a/tests/unit/proxy/common_utils/test_codex_model_catalog.py b/tests/unit/proxy/common_utils/test_codex_model_catalog.py index 16f507cc6fb..e700a39e1af 100644 --- a/tests/unit/proxy/common_utils/test_codex_model_catalog.py +++ b/tests/unit/proxy/common_utils/test_codex_model_catalog.py @@ -991,8 +991,14 @@ def test_a_key_for_an_openai_compatible_server_or_a_redirected_environment_never "api_key": "sk-internal-server", "api_base": "https://inference.internal.example/v1", }, + {"model": "openai/gpt-5.5", "api_key": "sk-through-the-gateway"}, {"model": "openai/gpt-5.5", "api_key": "sk-real-openai", "api_base": "https://api.openai.com/v1"}, ) - entries: Final = [(f"catalog-model-{index}", f"catalog-model-{index}") for index in range(2)] - assert codex_catalog_openai_key(router, entries[:1]) is None + entries: Final = [(f"catalog-model-{index}", f"catalog-model-{index}") for index in range(3)] + assert codex_catalog_openai_key(router, entries[:2]) is None assert codex_catalog_openai_key(router, entries) == "sk-real-openai" + monkeypatch.delenv("OPENAI_BASE_URL") + monkeypatch.setattr(litellm, "api_base", "https://llm-gateway.internal.example/v1") + assert codex_catalog_openai_key(router, entries[:2]) is None + monkeypatch.setattr(litellm, "api_base", None) + assert codex_catalog_openai_key(router, entries[:2]) == "sk-through-the-gateway"