From b88487e106d209ec286569115ca39658ad9909a5 Mon Sep 17 00:00:00 2001 From: Ishaan Jaff Date: Tue, 22 Apr 2025 18:01:56 -0700 Subject: [PATCH] streaming fixes --- .../llms/azure/responses/transformation.py | 50 ++++++++++++++++++- .../base_responses_api.py | 4 ++ 2 files changed, 53 insertions(+), 1 deletion(-) diff --git a/litellm/llms/azure/responses/transformation.py b/litellm/llms/azure/responses/transformation.py index f1480fa7ea..499d21cb0e 100644 --- a/litellm/llms/azure/responses/transformation.py +++ b/litellm/llms/azure/responses/transformation.py @@ -1,11 +1,14 @@ -from typing import TYPE_CHECKING, Any, Optional, cast +from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, cast import httpx import litellm +from litellm._logging import verbose_logger from litellm.llms.openai.responses.transformation import OpenAIResponsesAPIConfig from litellm.secret_managers.main import get_secret_str from litellm.types.llms.openai import * +from litellm.types.responses.main import * +from litellm.types.router import GenericLiteLLMParams from litellm.utils import _add_path_to_api_base if TYPE_CHECKING: @@ -88,3 +91,48 @@ class AzureOpenAIResponsesAPIConfig(OpenAIResponsesAPIConfig): final_url = httpx.URL(new_url).copy_with(params=query_params) return str(final_url) + + ######################################################### + ########## DELETE RESPONSE API TRANSFORMATION ############## + ######################################################### + def transform_delete_response_api_request( + self, + response_id: str, + api_base: str, + litellm_params: GenericLiteLLMParams, + headers: dict, + ) -> Tuple[str, Dict]: + """ + Transform the delete response API request into a URL and data + + Azure OpenAI API expects the following request: + - DELETE /openai/responses/{response_id}?api-version=xxx + + This function handles URLs with query parameters by inserting the response_id + at the correct location (before any query parameters). + """ + from urllib.parse import urlparse, urlunparse + + # Parse the URL to separate its components + parsed_url = urlparse(api_base) + + # Insert the response_id at the end of the path component + # Remove trailing slash if present to avoid double slashes + path = parsed_url.path.rstrip("/") + new_path = f"{path}/{response_id}" + + # Reconstruct the URL with all original components but with the modified path + delete_url = urlunparse( + ( + parsed_url.scheme, # http, https + parsed_url.netloc, # domain name, port + new_path, # path with response_id added + parsed_url.params, # parameters + parsed_url.query, # query string + parsed_url.fragment, # fragment + ) + ) + + data: Dict = {} + verbose_logger.debug(f"delete response url={delete_url}") + return delete_url, data diff --git a/tests/llm_responses_api_testing/base_responses_api.py b/tests/llm_responses_api_testing/base_responses_api.py index 1d9223bf86..905b9b3219 100644 --- a/tests/llm_responses_api_testing/base_responses_api.py +++ b/tests/llm_responses_api_testing/base_responses_api.py @@ -205,6 +205,7 @@ class BaseResponsesAPITest(ABC): if isinstance(response, ResponsesAPIResponse): litellm.delete_responses( response_id=response.id, + **base_completion_call_args ) else: raise ValueError("response is not a ResponsesAPIResponse") @@ -218,6 +219,7 @@ class BaseResponsesAPITest(ABC): if isinstance(response, ResponsesAPIResponse): await litellm.adelete_responses( response_id=response.id, + **base_completion_call_args ) else: raise ValueError("response is not a ResponsesAPIResponse") @@ -249,6 +251,7 @@ class BaseResponsesAPITest(ABC): assert response_id is not None litellm.delete_responses( response_id=response_id, + **base_completion_call_args ) else: response = await litellm.aresponses( @@ -268,6 +271,7 @@ class BaseResponsesAPITest(ABC): assert response_id is not None await litellm.adelete_responses( response_id=response_id, + **base_completion_call_args )