From 22344c37a90014c115cc0b1c73a9d777604ce784 Mon Sep 17 00:00:00 2001 From: Enjoy Kumawat Date: Wed, 8 Apr 2026 10:03:06 +0530 Subject: [PATCH 1/2] fix: warn on silent MIME type fallback and propagate model in recursive calls LiteLLM silently fell back to application/octet-stream when file_uri MIME type could not be determined, using only a debug log that was easy to miss. Upgrade to warning level so developers notice the fallback. Also fix _content_to_message_param() to propagate the model parameter in recursive calls for mixed function_response + content parts, which caused incorrect provider detection on Vertex AI / Anthropic. Fixes #5184 --- src/google/adk/models/lite_llm.py | 3 +- tests/unittests/models/test_litellm.py | 53 ++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/google/adk/models/lite_llm.py b/src/google/adk/models/lite_llm.py index 7d13696c96..e3803b8da9 100644 --- a/src/google/adk/models/lite_llm.py +++ b/src/google/adk/models/lite_llm.py @@ -811,6 +811,7 @@ async def _content_to_message_param( follow_up = await _content_to_message_param( types.Content(role=content.role, parts=non_tool_parts), provider=provider, + model=model, ) follow_up_messages = ( follow_up if isinstance(follow_up, list) else [follow_up] @@ -1091,7 +1092,7 @@ async def _get_content( if not mime_type: # LiteLLM's Vertex AI backend requires format for GCS URIs. mime_type = _DEFAULT_MIME_TYPE - logger.debug( + logger.warning( "Could not determine MIME type for file_uri %s, using default: %s", part.file_data.file_uri, mime_type, diff --git a/tests/unittests/models/test_litellm.py b/tests/unittests/models/test_litellm.py index ace08ad997..891bf4f984 100644 --- a/tests/unittests/models/test_litellm.py +++ b/tests/unittests/models/test_litellm.py @@ -4894,3 +4894,56 @@ async def test_content_to_message_param_anthropic_no_signature_falls_back(): # Falls back to reasoning_content when no signatures present assert result.get("reasoning_content") == "thinking without sig" assert "thinking_blocks" not in result + + +@pytest.mark.asyncio +async def test_content_to_message_param_file_uri_mime_fallback_logs_warning( + caplog, +): + """Test that falling back to application/octet-stream logs a warning.""" + file_part = types.Part( + file_data=types.FileData( + file_uri="gs://bucket/artifact/0" + ) + ) + content = types.Content( + role="user", + parts=[file_part], + ) + + with caplog.at_level(logging.WARNING, logger="google.adk.models.lite_llm"): + await _content_to_message_param(content) + + assert any( + "Could not determine MIME type" in record.message + for record in caplog.records + ), "Expected a warning about MIME type fallback" + + +@pytest.mark.asyncio +async def test_content_to_message_param_function_response_with_extra_parts_propagates_model(): + """Test that model parameter is propagated in recursive calls for mixed parts.""" + tool_part = types.Part.from_function_response( + name="load_image", + response={"status": "success"}, + ) + tool_part.function_response.id = "tool_call_1" + + text_part = types.Part.from_text(text="Here is the result") + + content = types.Content( + role="user", + parts=[tool_part, text_part], + ) + + # Call with model parameter — should not raise and should produce valid output + messages = await _content_to_message_param( + content, provider="anthropic", model="anthropic/claude-4-sonnet" + ) + assert isinstance(messages, list) + assert len(messages) == 2 + # First message is tool response + assert messages[0]["role"] == "tool" + assert messages[0]["tool_call_id"] == "tool_call_1" + # Second message is the text follow-up + assert messages[1]["role"] == "user" From c03864d4565e09bb4f662463e36fe91583bae671 Mon Sep 17 00:00:00 2001 From: Enjoy Kumawat Date: Thu, 9 Apr 2026 13:11:50 +0530 Subject: [PATCH 2/2] style: apply pyink formatting and add return type annotations --- tests/unittests/models/test_litellm.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/unittests/models/test_litellm.py b/tests/unittests/models/test_litellm.py index 891bf4f984..e92c5d1da3 100644 --- a/tests/unittests/models/test_litellm.py +++ b/tests/unittests/models/test_litellm.py @@ -4899,7 +4899,7 @@ async def test_content_to_message_param_anthropic_no_signature_falls_back(): @pytest.mark.asyncio async def test_content_to_message_param_file_uri_mime_fallback_logs_warning( caplog, -): +) -> None: """Test that falling back to application/octet-stream logs a warning.""" file_part = types.Part( file_data=types.FileData( @@ -4921,7 +4921,7 @@ async def test_content_to_message_param_file_uri_mime_fallback_logs_warning( @pytest.mark.asyncio -async def test_content_to_message_param_function_response_with_extra_parts_propagates_model(): +async def test_content_to_message_param_function_response_with_extra_parts_propagates_model() -> None: """Test that model parameter is propagated in recursive calls for mixed parts.""" tool_part = types.Part.from_function_response( name="load_image",