fix: guard against Content with no parts in _content_to_message_param
Merge https://github.com/google/adk-python/pull/6312 Avoid raising TypeError when types.Content has parts=None or parts=[] in LiteLLM adapter. PiperOrigin-RevId: 967357294
This commit is contained in:
committed by
Copybara-Service
parent
924d802f5b
commit
1ed8d48620
@@ -1233,7 +1233,7 @@ async def _content_to_message_param(
|
||||
*,
|
||||
provider: str = "",
|
||||
model: str = "",
|
||||
) -> Union[Message, list[Message]]:
|
||||
) -> Union[Message, list[Message]] | None:
|
||||
"""Converts a types.Content to a litellm Message or list of Messages.
|
||||
|
||||
Handles multipart function responses by returning a list of
|
||||
@@ -1245,14 +1245,18 @@ async def _content_to_message_param(
|
||||
model: The LiteLLM model string, used for provider-specific behavior.
|
||||
|
||||
Returns:
|
||||
A litellm Message, a list of litellm Messages.
|
||||
A litellm Message, a list of litellm Messages, or None if skipped.
|
||||
"""
|
||||
_ensure_litellm_imported()
|
||||
|
||||
# Skip content if there are no parts to avoid LiteLLM adapter errors.
|
||||
parts = content.parts or []
|
||||
if not parts:
|
||||
return None
|
||||
|
||||
tool_messages: list[Message] = []
|
||||
non_tool_parts: list[types.Part] = []
|
||||
content_parts_or_empty = content.parts or []
|
||||
for part in content_parts_or_empty:
|
||||
for part in parts:
|
||||
if part.function_response:
|
||||
function_response = part.function_response
|
||||
response = function_response.response
|
||||
@@ -1300,7 +1304,7 @@ async def _content_to_message_param(
|
||||
role = _to_litellm_role(content.role)
|
||||
|
||||
if role == "user":
|
||||
user_parts = [part for part in content_parts_or_empty if not part.thought]
|
||||
user_parts = [part for part in parts if not part.thought]
|
||||
message_content = (
|
||||
await _get_content(user_parts, provider=provider, model=model) or None
|
||||
)
|
||||
@@ -1312,7 +1316,7 @@ async def _content_to_message_param(
|
||||
tool_calls: list[_OutboundToolCall] = []
|
||||
content_parts: list[types.Part] = []
|
||||
reasoning_parts: list[types.Part] = []
|
||||
for part in content_parts_or_empty:
|
||||
for part in parts:
|
||||
if part.function_call:
|
||||
function_call = part.function_call
|
||||
if not function_call.name:
|
||||
|
||||
@@ -2085,6 +2085,23 @@ async def test_content_to_message_param_user_message():
|
||||
assert message["content"] == "Test prompt"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("parts", [None, []])
|
||||
async def test_content_to_message_param_user_message_without_parts(parts):
|
||||
# parts must not raise.
|
||||
content = types.Content(role="user", parts=parts)
|
||||
message = await _content_to_message_param(content)
|
||||
assert message is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("parts", [None, []])
|
||||
async def test_content_to_message_param_assistant_message_without_parts(parts):
|
||||
content = types.Content(role="assistant", parts=parts)
|
||||
message = await _content_to_message_param(content)
|
||||
assert message is None
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@pytest.mark.parametrize("file_uri,mime_type", FILE_URI_TEST_CASES)
|
||||
async def test_content_to_message_param_user_message_with_file_uri(
|
||||
|
||||
Reference in New Issue
Block a user