From 070446e4909b8417919fbdf678ea86aa29631b84 Mon Sep 17 00:00:00 2001 From: GeGeeWhy Date: Thu, 19 Feb 2026 16:17:55 +0800 Subject: [PATCH] feat: Add synchronous methods for format conversion compatible with Anthropic and Gemini. Co-authored-by: MrrDrr --- .../anthropic_interface/messages/__init__.py | 7 ++++--- litellm/google_genai/adapters/handler.py | 3 ++- .../google_genai/adapters/transformation.py | 10 ++++++++++ .../adapters/handler.py | 4 +++- .../adapters/transformation.py | 18 ++++++++++++++++++ .../messages/handler.py | 5 +++-- 6 files changed, 40 insertions(+), 7 deletions(-) diff --git a/litellm/anthropic_interface/messages/__init__.py b/litellm/anthropic_interface/messages/__init__.py index d7ff53a1763..8cf10fe1f4a 100644 --- a/litellm/anthropic_interface/messages/__init__.py +++ b/litellm/anthropic_interface/messages/__init__.py @@ -10,7 +10,7 @@ This is an __init__.py file to allow the following interface """ -from typing import Any, AsyncIterator, Coroutine, Dict, List, Optional, Union +from typing import Any, AsyncIterator, Coroutine, Dict, List, Optional, Union,Iterator from litellm.llms.anthropic.experimental_pass_through.messages.handler import ( anthropic_messages as _async_anthropic_messages, @@ -39,7 +39,7 @@ async def acreate( top_p: Optional[float] = None, container: Optional[Dict] = None, **kwargs -) -> Union[AnthropicMessagesResponse, AsyncIterator]: +) -> Union[AnthropicMessagesResponse, AsyncIterator, Iterator]: """ Async wrapper for Anthropic's messages API @@ -101,10 +101,11 @@ def create( ) -> Union[ AnthropicMessagesResponse, AsyncIterator[Any], + Iterator[Any], Coroutine[Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any]]], ]: """ - Async wrapper for Anthropic's messages API + Sync wrapper for Anthropic's messages API Args: max_tokens (int): Maximum tokens to generate (required) diff --git a/litellm/google_genai/adapters/handler.py b/litellm/google_genai/adapters/handler.py index 209e03d2bda..e450f98f7b5 100644 --- a/litellm/google_genai/adapters/handler.py +++ b/litellm/google_genai/adapters/handler.py @@ -1,4 +1,4 @@ -from typing import Any, AsyncIterator, Coroutine, Dict, List, Optional, Union, cast +from typing import Any, Iterator, AsyncIterator, Coroutine, Dict, List, Optional, Union, cast import litellm from litellm.types.router import GenericLiteLLMParams @@ -121,6 +121,7 @@ class GenerateContentToCompletionHandler: ) -> Union[ Dict[str, Any], AsyncIterator[bytes], + Iterator[bytes], Coroutine[Any, Any, Union[Dict[str, Any], AsyncIterator[bytes]]], ]: """Handle generate_content call using completion adapter""" diff --git a/litellm/google_genai/adapters/transformation.py b/litellm/google_genai/adapters/transformation.py index c5d9fd124fa..1818515ea87 100644 --- a/litellm/google_genai/adapters/transformation.py +++ b/litellm/google_genai/adapters/transformation.py @@ -321,6 +321,16 @@ class GoogleGenAIAdapter: ) # Return the SSE-wrapped version for proper event formatting return google_genai_wrapper.async_google_genai_sse_wrapper() + + def sync_translate_completion_output_params_streaming( + self, + completion_stream: Any, + ) -> Union[Iterator[bytes], None]: + """Sync version of transform streaming completion output to Google GenAI format""" + google_genai_wrapper = GoogleGenAIStreamWrapper( + completion_stream=completion_stream + ) + return google_genai_wrapper.google_genai_sse_wrapper() def _transform_google_genai_tools_to_openai( self, diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py b/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py index 897ca3bf893..49ddee8137a 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/handler.py @@ -2,6 +2,7 @@ from typing import ( TYPE_CHECKING, Any, AsyncIterator, + Iterator, Coroutine, Dict, List, @@ -292,6 +293,7 @@ class LiteLLMMessagesToCompletionTransformationHandler: ) -> Union[ AnthropicMessagesResponse, AsyncIterator[Any], + Iterator[Any], Coroutine[Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any]]], ]: """Handle non-Anthropic models using the adapter.""" @@ -339,7 +341,7 @@ class LiteLLMMessagesToCompletionTransformationHandler: if stream: transformed_stream = ( - ANTHROPIC_ADAPTER.translate_completion_output_params_streaming( + ANTHROPIC_ADAPTER.sync_translate_completion_output_params_streaming( completion_response, model=model, tool_name_mapping=tool_name_mapping, diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index ed49943b7fe..92c038e112e 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -5,6 +5,7 @@ from typing import ( TYPE_CHECKING, Any, AsyncIterator, + Iterator, Dict, List, Literal, @@ -228,6 +229,23 @@ class AnthropicAdapter: ) # Return the SSE-wrapped version for proper event formatting return anthropic_wrapper.async_anthropic_sse_wrapper() + + def sync_translate_completion_output_params_streaming( + self, + completion_stream: Any, + model: str, + tool_name_mapping: Optional[Dict[str, str]] = None, + ) -> Union[Iterator[bytes], None]: + """ + Synchronous version of translate_completion_output_params_streaming. + """ + anthropic_wrapper = AnthropicStreamWrapper( + completion_stream=completion_stream, + model=model, + tool_name_mapping=tool_name_mapping, + ) + # Use the synchronous wrapper for synchronous iteration + return anthropic_wrapper.anthropic_sse_wrapper() class LiteLLMAnthropicMessagesAdapter: diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py index d117d74e4f7..74cf6844197 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py @@ -8,7 +8,7 @@ import asyncio import contextvars from functools import partial -from typing import Any, AsyncIterator, Coroutine, Dict, List, Optional, Union, cast +from typing import Any, Iterator, AsyncIterator, Coroutine, Dict, List, Optional, Union, cast import litellm from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLoggingObj @@ -183,7 +183,7 @@ async def anthropic_messages( client: Optional[AsyncHTTPHandler] = None, custom_llm_provider: Optional[str] = None, **kwargs, -) -> Union[AnthropicMessagesResponse, AsyncIterator]: +) -> Union[AnthropicMessagesResponse, AsyncIterator, Iterator]: """ Async: Make llm api request in Anthropic /messages API spec """ @@ -308,6 +308,7 @@ def anthropic_messages_handler( ) -> Union[ AnthropicMessagesResponse, AsyncIterator[Any], + Iterator[Any], Coroutine[Any, Any, Union[AnthropicMessagesResponse, AsyncIterator[Any]]], ]: """