diff --git a/litellm/llms/anthropic/chat/transformation.py b/litellm/llms/anthropic/chat/transformation.py index d7ce6a5f8de..51143ff7090 100644 --- a/litellm/llms/anthropic/chat/transformation.py +++ b/litellm/llms/anthropic/chat/transformation.py @@ -1621,6 +1621,9 @@ class AnthropicConfig(AnthropicModelInfo, BaseConfig): if thinking_content is not None: reasoning_content += thinking_content + if "" in text_content: + text_content = text_content.split("", 1)[1].lstrip() + return ( text_content, citations, diff --git a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py index 149c1de5f8a..8d4f5933448 100644 --- a/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/adapters/transformation.py @@ -1249,10 +1249,14 @@ class LiteLLMAnthropicMessagesAdapter: ) # Handle text content - if choice.message.content is not None: + text_content = choice.message.content + if isinstance(text_content, str) and "" in text_content: + text_content = text_content.split("", 1)[1].lstrip() + + if text_content: new_content.append( AnthropicResponseContentBlockText( - type="text", text=choice.message.content + type="text", text=text_content ).model_dump() ) # Handle tool calls (in parallel to text content) diff --git a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py index c400d82b7cf..ebb045cbfad 100644 --- a/litellm/llms/anthropic/experimental_pass_through/messages/handler.py +++ b/litellm/llms/anthropic/experimental_pass_through/messages/handler.py @@ -45,6 +45,41 @@ def _should_route_to_responses_api(custom_llm_provider: Optional[str]) -> bool: return custom_llm_provider in _RESPONSES_API_PROVIDERS +def _sanitize_think_tag_text_blocks( + response: Union[AnthropicMessagesResponse, AsyncIterator] +) -> Union[AnthropicMessagesResponse, AsyncIterator]: + if not isinstance(response, dict): + return response + + content = response.get("content") + if not isinstance(content, list): + return response + + sanitized_content: List[Dict[str, Any]] = [] + for block in content: + if not isinstance(block, dict): + sanitized_content.append(block) + continue + + if block.get("type") != "text": + sanitized_content.append(block) + continue + + text = block.get("text") + if not isinstance(text, str) or "" not in text: + sanitized_content.append(block) + continue + + cleaned_text = text.split("", 1)[1].lstrip() + if cleaned_text: + sanitized_block = dict(block) + sanitized_block["text"] = cleaned_text + sanitized_content.append(sanitized_block) + + response["content"] = sanitized_content + return response + + ####### ENVIRONMENT VARIABLES ################### # Initialize any necessary instances or variables here base_llm_http_handler = BaseLLMHTTPHandler() @@ -286,7 +321,7 @@ async def anthropic_messages( response = await init_response else: response = init_response - return response + return _sanitize_think_tag_text_blocks(response) def validate_anthropic_api_metadata(metadata: Optional[Dict] = None) -> Optional[Dict]: @@ -421,10 +456,12 @@ def anthropic_messages_handler( **kwargs, ) if _should_route_to_responses_api(custom_llm_provider): - return LiteLLMMessagesToResponsesAPIHandler.anthropic_messages_handler( - **_shared_kwargs + return _sanitize_think_tag_text_blocks( + LiteLLMMessagesToResponsesAPIHandler.anthropic_messages_handler( + **_shared_kwargs + ) ) - return ( + return _sanitize_think_tag_text_blocks( LiteLLMMessagesToCompletionTransformationHandler.anthropic_messages_handler( **_shared_kwargs ) @@ -441,20 +478,22 @@ def anthropic_messages_handler( params=local_vars ) ) - return base_llm_http_handler.anthropic_messages_handler( - model=model, - messages=messages, - anthropic_messages_provider_config=anthropic_messages_provider_config, - anthropic_messages_optional_request_params=dict( - anthropic_messages_optional_request_params - ), - _is_async=is_async, - client=client, - custom_llm_provider=custom_llm_provider, - litellm_params=litellm_params, - logging_obj=litellm_logging_obj, - api_key=api_key, - api_base=api_base, - stream=stream, - kwargs=kwargs, + return _sanitize_think_tag_text_blocks( + base_llm_http_handler.anthropic_messages_handler( + model=model, + messages=messages, + anthropic_messages_provider_config=anthropic_messages_provider_config, + anthropic_messages_optional_request_params=dict( + anthropic_messages_optional_request_params + ), + _is_async=is_async, + client=client, + custom_llm_provider=custom_llm_provider, + litellm_params=litellm_params, + logging_obj=litellm_logging_obj, + api_key=api_key, + api_base=api_base, + stream=stream, + kwargs=kwargs, + ) )