fix: send the Accept-Encoding header through the OpenAI and Azure SDK clients

The previous commit reached the SDK-built clients by handing them the
client litellm builds, which also swapped in litellm's aiohttp transport
and its SSL, proxy-mount and timeout settings. That is a much larger
change than the header needs, and it took the files, batches and
assistants calls off httpx entirely.

Pass `default_headers` on the SDK constructors instead. The header is the
only thing that changes; every client keeps the transport, SSL settings,
proxy mounts and timeouts it had before.

Two `http_client` arguments are corrected along the way: the async image
variations client and the async Cloudflare AI Gateway client were both
handed the sync `litellm.client_session`, so a deployment that set one
would give an async client a sync transport.

The header helpers now return a `Mapping` rather than a fresh dict, which
keeps the new call sites off the mutable-structure budget.
This commit is contained in:
mateo-berri 2026-09-06 03:13:52 -07:00
parent b29ab360fc
commit 2a89e5b684
10 changed files with 53 additions and 37 deletions

View file

@ -57,7 +57,7 @@
"limit": 5570
},
"reportMissingTypeArgument": {
"limit": 15281
"limit": 15279
},
"reportMissingTypeStubs": {
"limit": 40
@ -99,7 +99,7 @@
"limit": 0
},
"reportUnknownArgumentType": {
"limit": 44358
"limit": 44347
},
"reportUnknownLambdaType": {
"limit": 109
@ -108,10 +108,10 @@
"limit": 38271
},
"reportUnknownParameterType": {
"limit": 19584
"limit": 19582
},
"reportUnknownVariableType": {
"limit": 29814
"limit": 29806
},
"reportUnnecessaryCast": {
"limit": 110

View file

@ -15,6 +15,7 @@ import litellm
from litellm._logging import verbose_logger
from litellm.caching.caching import DualCache
from litellm.llms.base_llm.chat.transformation import BaseLLMException
from litellm.llms.custom_httpx.accept_encoding import accept_encoding_header
from litellm.llms.openai.common_utils import BaseOpenAILLM
from litellm.secret_managers.get_azure_ad_token_provider import (
get_azure_ad_token_provider,
@ -685,7 +686,8 @@ class BaseAzureLLM(BaseOpenAILLM):
azure_client_params: Final[_AzureGatewayClientParams] = {
"api_version": api_version,
"base_url": f"{api_base}",
"http_client": (self._get_async_http_client() if acompletion else self._get_sync_http_client()),
"http_client": (litellm.aclient_session if acompletion else litellm.client_session),
"default_headers": accept_encoding_header(),
"max_retries": max_retries,
"timeout": timeout,
}

View file

@ -132,7 +132,7 @@ def _build_aiohttp_keepalive_socket_factory() -> Callable[[_AddrInfo], socket.so
return factory
def get_default_headers() -> dict[str, str]:
def get_default_headers() -> Mapping[str, str]:
"""
Get default headers for HTTP requests.
@ -141,7 +141,9 @@ def get_default_headers() -> dict[str, str]:
"""
user_agent: Final = os.environ.get("LITELLM_USER_AGENT")
return {**accept_encoding_header(), "User-Agent": user_agent if user_agent is not None else f"litellm/{version}"}
return MappingProxyType(
{**accept_encoding_header(), "User-Agent": user_agent if user_agent is not None else f"litellm/{version}"}
)
# Initialize headers (User-Agent)

View file

@ -1,4 +1,6 @@
import os
from collections.abc import Mapping
from types import MappingProxyType
from typing import Final
import httpx
@ -11,7 +13,7 @@ except Exception:
version = "0.0.0"
def get_default_headers() -> dict:
def get_default_headers() -> Mapping[str, str]:
"""
Get default headers for HTTP requests.
@ -20,7 +22,9 @@ def get_default_headers() -> dict:
"""
user_agent: Final = os.environ.get("LITELLM_USER_AGENT")
return {**accept_encoding_header(), "User-Agent": user_agent if user_agent is not None else f"litellm/{version}"}
return MappingProxyType(
{**accept_encoding_header(), "User-Agent": user_agent if user_agent is not None else f"litellm/{version}"}
)
class HTTPHandler:

View file

@ -4,9 +4,11 @@ from typing import Final
from openai import AsyncOpenAI, OpenAI
import litellm
from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj
from litellm.litellm_core_utils.streaming_handler import CustomStreamWrapper
from litellm.llms.base import BaseLLM
from litellm.llms.custom_httpx.accept_encoding import accept_encoding_header
from litellm.types.llms.openai import AllMessageValues, OpenAITextCompletionUserMessage
from litellm.types.utils import LlmProviders, ModelResponse, TextCompletionResponse
from litellm.utils import ProviderConfigManager
@ -15,7 +17,7 @@ from ..common_utils import BaseOpenAILLM, OpenAIError
from .transformation import OpenAITextCompletionConfig
class OpenAITextCompletion(BaseLLM, BaseOpenAILLM):
class OpenAITextCompletion(BaseLLM):
openai_text_completion_global_config = OpenAITextCompletionConfig()
def __init__(self) -> None:
@ -128,7 +130,8 @@ class OpenAITextCompletion(BaseLLM, BaseOpenAILLM):
openai_client = OpenAI(
api_key=api_key,
base_url=api_base,
http_client=self._get_sync_http_client(),
http_client=litellm.client_session,
default_headers=accept_encoding_header(),
timeout=timeout,
max_retries=max_retries,
organization=organization,
@ -180,7 +183,7 @@ class OpenAITextCompletion(BaseLLM, BaseOpenAILLM):
openai_aclient = AsyncOpenAI(
api_key=api_key,
base_url=api_base,
http_client=self._get_async_http_client(),
http_client=BaseOpenAILLM._get_async_http_client(),
timeout=timeout,
max_retries=max_retries,
organization=organization,
@ -232,7 +235,8 @@ class OpenAITextCompletion(BaseLLM, BaseOpenAILLM):
openai_client = OpenAI(
api_key=api_key,
base_url=api_base,
http_client=self._get_sync_http_client(),
http_client=litellm.client_session,
default_headers=accept_encoding_header(),
timeout=timeout,
max_retries=max_retries,
organization=organization,
@ -289,7 +293,8 @@ class OpenAITextCompletion(BaseLLM, BaseOpenAILLM):
openai_client = AsyncOpenAI(
api_key=api_key,
base_url=api_base,
http_client=self._get_async_http_client(),
http_client=litellm.aclient_session,
default_headers=accept_encoding_header(),
timeout=timeout,
max_retries=max_retries,
organization=organization,

View file

@ -6,7 +6,7 @@ from openai import AsyncAzureOpenAI, AsyncOpenAI, AzureOpenAI, OpenAI
from openai.types.fine_tuning import FineTuningJob
from litellm._logging import verbose_logger
from litellm.llms.openai.common_utils import BaseOpenAILLM
from litellm.llms.custom_httpx.accept_encoding import accept_encoding_header
from litellm.types.utils import LiteLLMFineTuningJob
_AZURE_STATUS_MAP: Final[Mapping[object, str]] = {
@ -53,7 +53,7 @@ def _litellm_fine_tuning_job_from_response(response: FineTuningJob, is_azure: bo
return LiteLLMFineTuningJob(**_normalize_fine_tuning_job_dict(response.model_dump(), is_azure=is_azure))
class OpenAIFineTuningAPI(BaseOpenAILLM):
class OpenAIFineTuningAPI:
"""
OpenAI methods to support for batches
"""
@ -85,9 +85,9 @@ class OpenAIFineTuningAPI(BaseOpenAILLM):
elif v is not None:
data[k] = v
if _is_async is True:
openai_client = AsyncOpenAI(**data, http_client=self._get_async_http_client())
openai_client = AsyncOpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = OpenAI(**data, http_client=self._get_sync_http_client())
openai_client = OpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = client

View file

@ -8,15 +8,17 @@ from typing import Final
import httpx
from openai import AsyncOpenAI, OpenAI
import litellm
from litellm.llms.custom_httpx.accept_encoding import accept_encoding_header
from litellm.types.utils import FileTypes, ImageResponse, LlmProviders
from litellm.utils import ProviderConfigManager
from ...base_llm.image_variations.transformation import BaseImageVariationConfig
from ...custom_httpx.llm_http_handler import LiteLLMLoggingObj
from ..common_utils import BaseOpenAILLM, OpenAIError
from ..common_utils import OpenAIError
class OpenAIImageVariationsHandler(BaseOpenAILLM):
class OpenAIImageVariationsHandler:
def get_sync_client(
self,
client: OpenAI | None,
@ -25,7 +27,6 @@ class OpenAIImageVariationsHandler(BaseOpenAILLM):
if client is None:
openai_client = OpenAI(
**init_client_params,
http_client=self._get_sync_http_client(),
)
else:
openai_client = client
@ -35,7 +36,6 @@ class OpenAIImageVariationsHandler(BaseOpenAILLM):
if client is None:
openai_client = AsyncOpenAI(
**init_client_params,
http_client=self._get_async_http_client(),
)
else:
openai_client = client
@ -63,6 +63,8 @@ class OpenAIImageVariationsHandler(BaseOpenAILLM):
init_client_params: Final = {
"api_key": api_key,
"base_url": api_base,
"http_client": litellm.client_session,
"default_headers": accept_encoding_header(),
"timeout": timeout,
"max_retries": max_retries,
"organization": organization,
@ -179,6 +181,8 @@ class OpenAIImageVariationsHandler(BaseOpenAILLM):
init_client_params: Final = {
"api_key": api_key,
"base_url": api_base,
"http_client": litellm.aclient_session,
"default_headers": accept_encoding_header(),
"timeout": timeout,
"max_retries": max_retries,
"organization": organization,

View file

@ -31,6 +31,7 @@ from litellm.litellm_core_utils.logging_utils import speech_request_body, track_
from litellm.llms.base_llm.base_model_iterator import BaseModelResponseIterator
from litellm.llms.base_llm.chat.transformation import BaseConfig, BaseLLMException
from litellm.llms.bedrock.chat.invoke_handler import MockResponseIterator
from litellm.llms.custom_httpx.accept_encoding import accept_encoding_header
from litellm.types.utils import (
EmbeddingResponse,
ImageResponse,
@ -1660,7 +1661,7 @@ class OpenAIChatCompletion(BaseLLM, BaseOpenAILLM):
return HttpxBinaryResponseContent(response=response.response)
class OpenAIFilesAPI(BaseLLM, BaseOpenAILLM):
class OpenAIFilesAPI(BaseLLM):
"""
OpenAI methods to support for batches
- create_file()
@ -1696,9 +1697,9 @@ class OpenAIFilesAPI(BaseLLM, BaseOpenAILLM):
elif v is not None:
data[k] = v
if _is_async is True:
openai_client = AsyncOpenAI(**data, http_client=self._get_async_http_client())
openai_client = AsyncOpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = OpenAI(**data, http_client=self._get_sync_http_client())
openai_client = OpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = client
@ -2020,7 +2021,7 @@ class OpenAIFilesAPI(BaseLLM, BaseOpenAILLM):
return response
class OpenAIBatchesAPI(BaseLLM, BaseOpenAILLM):
class OpenAIBatchesAPI(BaseLLM):
"""
OpenAI methods to support for batches
- create_batch()
@ -2054,9 +2055,9 @@ class OpenAIBatchesAPI(BaseLLM, BaseOpenAILLM):
elif v is not None:
data[k] = v
if _is_async is True:
openai_client = AsyncOpenAI(**data, http_client=self._get_async_http_client())
openai_client = AsyncOpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = OpenAI(**data, http_client=self._get_sync_http_client())
openai_client = OpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = client
@ -2241,7 +2242,7 @@ class OpenAIBatchesAPI(BaseLLM, BaseOpenAILLM):
return response
class OpenAIAssistantsAPI(BaseLLM, BaseOpenAILLM):
class OpenAIAssistantsAPI(BaseLLM):
def __init__(self) -> None:
super().__init__()
@ -2264,7 +2265,7 @@ class OpenAIAssistantsAPI(BaseLLM, BaseOpenAILLM):
data["base_url"] = v
elif v is not None:
data[k] = v
openai_client = OpenAI(**data, http_client=self._get_sync_http_client())
openai_client = OpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = client
@ -2289,7 +2290,7 @@ class OpenAIAssistantsAPI(BaseLLM, BaseOpenAILLM):
data["base_url"] = v
elif v is not None:
data[k] = v
openai_client = AsyncOpenAI(**data, http_client=self._get_async_http_client())
openai_client = AsyncOpenAI(**data, default_headers=accept_encoding_header())
else:
openai_client = client

View file

@ -7531,11 +7531,9 @@ def moderation(input: str, model: str | None = None, api_key: str | None = None,
openai_client = kwargs.get("client", None)
if openai_client is None:
if api_base is not None:
openai_client = openai.OpenAI(
api_key=api_key, base_url=api_base, default_headers=dict(accept_encoding_header())
)
openai_client = openai.OpenAI(api_key=api_key, base_url=api_base, default_headers=accept_encoding_header())
else:
openai_client = openai.OpenAI(api_key=api_key, default_headers=dict(accept_encoding_header()))
openai_client = openai.OpenAI(api_key=api_key, default_headers=accept_encoding_header())
if model is not None:
response = openai_client.moderations.create(input=input, model=model)

View file

@ -1,9 +1,9 @@
{
"LIT001": {
"limit": 22180
"limit": 22178
},
"LIT002": {
"limit": 26729
"limit": 26725
},
"LIT003": {
"limit": 261