mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-19 00:01:29 +00:00
fix(realtime): dial Azure's GA realtime upstream for GA clients
Azure realtime defaulted to the beta upstream whenever realtime_protocol was not configured, so a GA client's session.update (session.type, output_modalities, nested audio) was forwarded unchanged to /openai/realtime and Azure rejected it with "Unknown parameter: 'session.type'" on gpt-realtime and gpt-realtime-1.5. The unset default now follows the client the way the OpenAI handler already does: a client that sends OpenAI-Beta: realtime=v1 keeps the beta upstream, any other client gets /openai/v1/realtime. An explicit realtime_protocol in litellm_params or LITELLM_AZURE_REALTIME_PROTOCOL still wins.
This commit is contained in:
parent
692a311efb
commit
8deb465346
2 changed files with 74 additions and 7 deletions
|
|
@ -14,6 +14,7 @@ from litellm.constants import (
|
|||
request_timeout,
|
||||
)
|
||||
from litellm.litellm_core_utils.get_llm_provider_logic import get_llm_provider
|
||||
from litellm.litellm_core_utils.realtime_streaming import client_sent_openai_beta_realtime_header
|
||||
from litellm.llms.base_llm.realtime.transformation import BaseRealtimeConfig
|
||||
from litellm.llms.custom_httpx.llm_http_handler import BaseLLMHTTPHandler
|
||||
from litellm.llms.xai.common_utils import XAIModelInfo
|
||||
|
|
@ -413,14 +414,14 @@ async def _arealtime(
|
|||
|
||||
api_version = api_version or litellm_params.api_version or "2024-10-01-preview"
|
||||
|
||||
realtime_protocol = (
|
||||
configured_realtime_protocol: Final = (
|
||||
kwargs.get("realtime_protocol")
|
||||
or litellm_params.get("realtime_protocol")
|
||||
or os.environ.get("LITELLM_AZURE_REALTIME_PROTOCOL")
|
||||
)
|
||||
if realtime_protocol is None and (query_params or {}).get("intent") == "transcription":
|
||||
realtime_protocol = "GA"
|
||||
realtime_protocol = realtime_protocol or "beta"
|
||||
realtime_protocol: Final = _azure_realtime_protocol_for_client(
|
||||
configured_realtime_protocol, query_params=query_params, websocket=websocket
|
||||
)
|
||||
resolved_azure_ad_token: Final = (
|
||||
None if api_key else get_azure_ad_token(GenericLiteLLMParams(**kwargs, azure_ad_token=azure_ad_token))
|
||||
)
|
||||
|
|
@ -576,6 +577,19 @@ def _is_transcription_only_realtime_model(model: str, custom_llm_provider: str)
|
|||
_TRANSCRIPTION_QUERY_PARAMS: Final[RealtimeQueryParams] = {"intent": "transcription"}
|
||||
|
||||
|
||||
def _azure_realtime_protocol_for_client(
|
||||
configured_protocol: object,
|
||||
*,
|
||||
query_params: RealtimeQueryParams | None,
|
||||
websocket: "WebSocket",
|
||||
) -> str:
|
||||
if isinstance(configured_protocol, str) and configured_protocol:
|
||||
return configured_protocol
|
||||
if (query_params or {}).get("intent") == "transcription":
|
||||
return "GA"
|
||||
return "beta" if client_sent_openai_beta_realtime_header(websocket) else "GA"
|
||||
|
||||
|
||||
def _azure_realtime_health_protocol(
|
||||
model: str, realtime_protocol: str | None, model_params: Mapping[str, object]
|
||||
) -> tuple[str, RealtimeQueryParams | None]:
|
||||
|
|
|
|||
|
|
@ -327,7 +327,60 @@ async def test_arealtime_azure_ai_on_a_foundry_host_connects_to_the_azure_openai
|
|||
api_key="fake-key",
|
||||
litellm_logging_obj=FakeLogging(),
|
||||
)
|
||||
assert connect.url == (
|
||||
"wss://my-project.services.ai.azure.com/openai/realtime"
|
||||
"?api-version=2024-10-01-preview&deployment=gpt-realtime-mini"
|
||||
assert connect.url == "wss://my-project.services.ai.azure.com/openai/v1/realtime?model=gpt-realtime-mini"
|
||||
|
||||
|
||||
class _ClientWebSocketWithHeaders:
|
||||
def __init__(self, headers: tuple[tuple[bytes, bytes], ...]) -> None:
|
||||
self.scope: Final = {"headers": headers}
|
||||
|
||||
|
||||
_GA_CLIENT: Final = _ClientWebSocketWithHeaders(headers=())
|
||||
_BETA_CLIENT: Final = _ClientWebSocketWithHeaders(headers=((b"openai-beta", b"realtime=v1"),))
|
||||
|
||||
|
||||
async def _azure_backend_url_dialed_for(websocket: _ClientWebSocketWithHeaders, **kwargs: object) -> str | None:
|
||||
connect: Final = _ConnectThatStopsAfterCapturingTheUrl()
|
||||
with patch("websockets.connect", connect):
|
||||
await realtime_main._arealtime.__wrapped__(
|
||||
model="azure/gpt-realtime",
|
||||
websocket=websocket,
|
||||
api_base="https://my-endpoint.openai.azure.com",
|
||||
api_key="fake-key",
|
||||
litellm_logging_obj=FakeLogging(),
|
||||
**kwargs,
|
||||
)
|
||||
return connect.url
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_arealtime_azure_ga_client_without_beta_header_dials_the_ga_upstream(monkeypatch):
|
||||
monkeypatch.delenv("LITELLM_AZURE_REALTIME_PROTOCOL", raising=False)
|
||||
assert (
|
||||
await _azure_backend_url_dialed_for(_GA_CLIENT)
|
||||
== "wss://my-endpoint.openai.azure.com/openai/v1/realtime?model=gpt-realtime"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_arealtime_azure_beta_header_client_keeps_the_beta_upstream(monkeypatch):
|
||||
monkeypatch.delenv("LITELLM_AZURE_REALTIME_PROTOCOL", raising=False)
|
||||
assert await _azure_backend_url_dialed_for(_BETA_CLIENT) == (
|
||||
"wss://my-endpoint.openai.azure.com/openai/realtime?api-version=2024-10-01-preview&deployment=gpt-realtime"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_arealtime_azure_explicit_beta_protocol_wins_over_a_ga_client(monkeypatch):
|
||||
monkeypatch.delenv("LITELLM_AZURE_REALTIME_PROTOCOL", raising=False)
|
||||
assert await _azure_backend_url_dialed_for(_GA_CLIENT, realtime_protocol="beta") == (
|
||||
"wss://my-endpoint.openai.azure.com/openai/realtime?api-version=2024-10-01-preview&deployment=gpt-realtime"
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_arealtime_azure_env_beta_protocol_wins_over_a_ga_client(monkeypatch):
|
||||
monkeypatch.setenv("LITELLM_AZURE_REALTIME_PROTOCOL", "beta")
|
||||
assert await _azure_backend_url_dialed_for(_GA_CLIENT) == (
|
||||
"wss://my-endpoint.openai.azure.com/openai/realtime?api-version=2024-10-01-preview&deployment=gpt-realtime"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue