Skip to content

Commit d149537

Browse files
committed
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
1 parent 114deef commit d149537

2 files changed

Lines changed: 55 additions & 1 deletion

File tree

src/google/adk/models/lite_llm.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,7 @@ async def _content_to_message_param(
811811
follow_up = await _content_to_message_param(
812812
types.Content(role=content.role, parts=non_tool_parts),
813813
provider=provider,
814+
model=model,
814815
)
815816
follow_up_messages = (
816817
follow_up if isinstance(follow_up, list) else [follow_up]
@@ -1091,7 +1092,7 @@ async def _get_content(
10911092
if not mime_type:
10921093
# LiteLLM's Vertex AI backend requires format for GCS URIs.
10931094
mime_type = _DEFAULT_MIME_TYPE
1094-
logger.debug(
1095+
logger.warning(
10951096
"Could not determine MIME type for file_uri %s, using default: %s",
10961097
part.file_data.file_uri,
10971098
mime_type,

tests/unittests/models/test_litellm.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4894,3 +4894,56 @@ async def test_content_to_message_param_anthropic_no_signature_falls_back():
48944894
# Falls back to reasoning_content when no signatures present
48954895
assert result.get("reasoning_content") == "thinking without sig"
48964896
assert "thinking_blocks" not in result
4897+
4898+
4899+
@pytest.mark.asyncio
4900+
async def test_content_to_message_param_file_uri_mime_fallback_logs_warning(
4901+
caplog,
4902+
):
4903+
"""Test that falling back to application/octet-stream logs a warning."""
4904+
file_part = types.Part(
4905+
file_data=types.FileData(
4906+
file_uri="gs://bucket/artifact/0"
4907+
)
4908+
)
4909+
content = types.Content(
4910+
role="user",
4911+
parts=[file_part],
4912+
)
4913+
4914+
with caplog.at_level(logging.WARNING, logger="google.adk.models.lite_llm"):
4915+
await _content_to_message_param(content)
4916+
4917+
assert any(
4918+
"Could not determine MIME type" in record.message
4919+
for record in caplog.records
4920+
), "Expected a warning about MIME type fallback"
4921+
4922+
4923+
@pytest.mark.asyncio
4924+
async def test_content_to_message_param_function_response_with_extra_parts_propagates_model():
4925+
"""Test that model parameter is propagated in recursive calls for mixed parts."""
4926+
tool_part = types.Part.from_function_response(
4927+
name="load_image",
4928+
response={"status": "success"},
4929+
)
4930+
tool_part.function_response.id = "tool_call_1"
4931+
4932+
text_part = types.Part.from_text(text="Here is the result")
4933+
4934+
content = types.Content(
4935+
role="user",
4936+
parts=[tool_part, text_part],
4937+
)
4938+
4939+
# Call with model parameter — should not raise and should produce valid output
4940+
messages = await _content_to_message_param(
4941+
content, provider="anthropic", model="anthropic/claude-4-sonnet"
4942+
)
4943+
assert isinstance(messages, list)
4944+
assert len(messages) == 2
4945+
# First message is tool response
4946+
assert messages[0]["role"] == "tool"
4947+
assert messages[0]["tool_call_id"] == "tool_call_1"
4948+
# Second message is the text follow-up
4949+
assert messages[1]["role"] == "user"

0 commit comments

Comments
 (0)