diff --git a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py index 2badc2a3276..03e0ba274de 100644 --- a/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py +++ b/litellm/llms/anthropic/experimental_pass_through/responses_adapters/transformation.py @@ -165,12 +165,10 @@ class LiteLLMAnthropicToResponsesAPIAdapter: "arguments": json.dumps(block.get("input", {})), } ) - elif btype == "thinking": - thinking_text = block.get("thinking", "") - if thinking_text: - asst_parts.append( - {"type": "output_text", "text": thinking_text} - ) + elif btype in ("thinking", "redacted_thinking"): + # Anthropic thinking blocks are hidden reasoning state, + # not assistant-visible output for OpenAI Responses. + continue if asst_parts: input_items.append( { diff --git a/tests/test_litellm/llms/anthropic/experimental_pass_through/responses_adapters/test_responses_adapters_transformation.py b/tests/test_litellm/llms/anthropic/experimental_pass_through/responses_adapters/test_responses_adapters_transformation.py index 02b817cd334..7827e9ee3f5 100644 --- a/tests/test_litellm/llms/anthropic/experimental_pass_through/responses_adapters/test_responses_adapters_transformation.py +++ b/tests/test_litellm/llms/anthropic/experimental_pass_through/responses_adapters/test_responses_adapters_transformation.py @@ -394,21 +394,43 @@ class TestTranslateMessagesToResponsesInput: } ] - def test_assistant_thinking_block_becomes_output_text(self): - """Assistant thinking block text is included as output_text.""" + def test_assistant_thinking_block_is_not_sent_as_output_text(self): + """Assistant thinking blocks are hidden reasoning state, not visible output.""" messages = [ { "role": "assistant", "content": [ - {"type": "thinking", "thinking": "Let me reason step by step."} + { + "type": "thinking", + "thinking": "Let me reason step by step.", + "signature": "sig_abc", + }, + {"type": "text", "text": "Here is the answer."}, ], } ] result = _translate_messages(messages) assert result[0]["content"] == [ - {"type": "output_text", "text": "Let me reason step by step."} + {"type": "output_text", "text": "Here is the answer."} ] + def test_assistant_only_thinking_block_skipped(self): + """Assistant messages with only thinking blocks are omitted on replay.""" + messages = [ + { + "role": "assistant", + "content": [ + { + "type": "thinking", + "thinking": "Hidden reasoning", + "signature": "sig_abc", + } + ], + } + ] + result = _translate_messages(messages) + assert result == [] + def test_assistant_empty_thinking_block_skipped(self): """Assistant thinking block with empty thinking text is skipped.""" messages = [ @@ -420,6 +442,22 @@ class TestTranslateMessagesToResponsesInput: result = _translate_messages(messages) assert result == [] + def test_assistant_redacted_thinking_block_skipped(self): + """Redacted thinking blocks should not be replayed as visible text.""" + messages = [ + { + "role": "assistant", + "content": [ + {"type": "redacted_thinking", "data": "encrypted-state"}, + {"type": "text", "text": "Visible answer."}, + ], + } + ] + result = _translate_messages(messages) + assert result[0]["content"] == [ + {"type": "output_text", "text": "Visible answer."} + ] + def test_mixed_messages_ordering(self): """Full multi-turn conversation is converted in order.""" messages = [