diff --git a/src/strands/models/llamaapi.py b/src/strands/models/llamaapi.py index b1ed4563a..d9280b7e1 100644 --- a/src/strands/models/llamaapi.py +++ b/src/strands/models/llamaapi.py @@ -179,7 +179,7 @@ def _format_request_messages(self, messages: Messages, system_prompt: str | None # Filter out location sources and unsupported block types filtered_contents = [] for content in contents: - if any(block_type in content for block_type in ["toolResult", "toolUse"]): + if any(block_type in content for block_type in ["toolResult", "toolUse", "reasoningContent"]): continue if _has_location_source(content): logger.warning("Location sources are not supported by LlamaAPI | skipping content block") diff --git a/src/strands/models/llamacpp.py b/src/strands/models/llamacpp.py index c52509816..6e8dab149 100644 --- a/src/strands/models/llamacpp.py +++ b/src/strands/models/llamacpp.py @@ -302,7 +302,7 @@ def _format_messages(self, messages: Messages, system_prompt: str | None = None) # Filter out location sources and unsupported block types filtered_contents = [] for content in contents: - if any(block_type in content for block_type in ["toolResult", "toolUse"]): + if any(block_type in content for block_type in ["toolResult", "toolUse", "reasoningContent"]): continue if _has_location_source(content): logger.warning("Location sources are not supported by llama.cpp | skipping content block") diff --git a/src/strands/models/writer.py b/src/strands/models/writer.py index 94774b363..0e774134f 100644 --- a/src/strands/models/writer.py +++ b/src/strands/models/writer.py @@ -116,7 +116,7 @@ def _format_content_vision(content: ContentBlock) -> dict[str, Any]: return [ _format_content_vision(content) for content in contents - if not any(block_type in content for block_type in ["toolResult", "toolUse"]) + if not any(block_type in content for block_type in ["toolResult", "toolUse", "reasoningContent"]) ] def _format_request_message_contents(self, contents: list[ContentBlock]) -> str: @@ -142,7 +142,7 @@ def _format_content(content: ContentBlock) -> str: content_blocks = list( filter( lambda content: content.get("text") - and not any(block_type in content for block_type in ["toolResult", "toolUse"]), + and not any(block_type in content for block_type in ["toolResult", "toolUse", "reasoningContent"]), contents, ) ) diff --git a/tests/strands/models/test_llamaapi.py b/tests/strands/models/test_llamaapi.py index 2bf12d055..8047e6a35 100644 --- a/tests/strands/models/test_llamaapi.py +++ b/tests/strands/models/test_llamaapi.py @@ -241,6 +241,26 @@ def test_format_request_with_unsupported_type(model): model.format_request(messages) +def test_format_request_skips_reasoning_content(model): + """Test that reasoningContent blocks from other providers are silently skipped.""" + messages = [ + { + "role": "user", + "content": [ + {"text": "Hello"}, + {"reasoningContent": {"reasoningText": {"text": "Let me think...", "signature": "sig"}}}, + ], + }, + ] + + # Should not raise — reasoningContent is silently dropped + request = model.format_request(messages) + # Only the text block should appear in the formatted request + user_messages = [m for m in request["messages"] if m["role"] == "user"] + assert len(user_messages) == 1 + assert user_messages[0]["content"] == [{"type": "text", "text": "Hello"}] + + def test_format_chunk_message_start(model): event = {"chunk_type": "message_start"} diff --git a/tests/strands/models/test_llamacpp.py b/tests/strands/models/test_llamacpp.py index 3e023dfce..e3815ca0d 100644 --- a/tests/strands/models/test_llamacpp.py +++ b/tests/strands/models/test_llamacpp.py @@ -706,3 +706,25 @@ def test_format_request_filters_location_source_document(caplog) -> None: assert len(user_content) == 1 assert user_content[0]["type"] == "text" assert "Location sources are not supported by llama.cpp" in caplog.text + + +def test_format_request_skips_reasoning_content() -> None: + """Test that reasoningContent blocks from other providers are silently skipped.""" + model = LlamaCppModel() + + messages = [ + { + "role": "user", + "content": [ + {"text": "Hello"}, + {"reasoningContent": {"reasoningText": {"text": "Let me think...", "signature": "sig"}}}, + ], + }, + ] + + # Should not raise — reasoningContent is silently dropped + request = model._format_request(messages) + # Only the text block should appear in the formatted request + user_messages = [m for m in request["messages"] if m["role"] == "user"] + assert len(user_messages) == 1 + assert user_messages[0]["content"] == [{"type": "text", "text": "Hello"}] diff --git a/tests/strands/models/test_writer.py b/tests/strands/models/test_writer.py index 81745f412..497b9cba3 100644 --- a/tests/strands/models/test_writer.py +++ b/tests/strands/models/test_writer.py @@ -250,7 +250,6 @@ def test_format_request_with_empty_content(model, model_id, stream_options): [ ({"video": {}}, "video"), ({"document": {}}, "document"), - ({"reasoningContent": {}}, "reasoningContent"), ({"other": {}}, "other"), ], ) @@ -266,6 +265,22 @@ def test_format_request_with_unsupported_type(model, content, content_type): model.format_request(messages) +def test_format_request_skips_reasoning_content(model): + """Test that reasoningContent blocks from other providers are silently skipped.""" + messages = [ + { + "role": "user", + "content": [ + {"text": "Hello"}, + {"reasoningContent": {"reasoningText": {"text": "Let me think...", "signature": "sig"}}}, + ], + }, + ] + + # Should not raise — reasoningContent is silently dropped + model.format_request(messages) + + class AsyncStreamWrapper: def __init__(self, items: list[Any]): self.items = items