mirror of
https://github.com/encounter/adk-python.git
synced 2026-07-09 18:19:28 -07:00
fix: Add a fallback user message to LiteLLM requests if the last user message is empty
Related to #3255 Close #2560 PiperOrigin-RevId: 825143315
This commit is contained in:
committed by
Copybara-Service
parent
240ef5beea
commit
74d8361a7e
@@ -155,6 +155,53 @@ def _safe_json_serialize(obj) -> str:
|
||||
return str(obj)
|
||||
|
||||
|
||||
def _part_has_payload(part: types.Part) -> bool:
|
||||
"""Checks whether a Part contains usable payload for the model."""
|
||||
if part.text:
|
||||
return True
|
||||
if part.inline_data and part.inline_data.data:
|
||||
return True
|
||||
if part.file_data and (part.file_data.file_uri or part.file_data.data):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def _append_fallback_user_content_if_missing(
|
||||
llm_request: LlmRequest,
|
||||
) -> None:
|
||||
"""Ensures there is a user message with content for LiteLLM backends.
|
||||
|
||||
Args:
|
||||
llm_request: The request that may need a fallback user message.
|
||||
"""
|
||||
for content in reversed(llm_request.contents):
|
||||
if content.role == "user":
|
||||
parts = content.parts or []
|
||||
if any(_part_has_payload(part) for part in parts):
|
||||
return
|
||||
if not parts:
|
||||
content.parts = []
|
||||
content.parts.append(
|
||||
types.Part.from_text(
|
||||
text="Handle the requests as specified in the System Instruction."
|
||||
)
|
||||
)
|
||||
return
|
||||
llm_request.contents.append(
|
||||
types.Content(
|
||||
role="user",
|
||||
parts=[
|
||||
types.Part.from_text(
|
||||
text=(
|
||||
"Handle the requests as specified in the System"
|
||||
" Instruction."
|
||||
)
|
||||
),
|
||||
],
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def _content_to_message_param(
|
||||
content: types.Content,
|
||||
) -> Union[Message, list[Message]]:
|
||||
@@ -818,6 +865,7 @@ class LiteLlm(BaseLlm):
|
||||
"""
|
||||
|
||||
self._maybe_append_user_content(llm_request)
|
||||
_append_fallback_user_content_if_missing(llm_request)
|
||||
logger.debug(_build_request_log(llm_request))
|
||||
|
||||
messages, tools, response_format, generation_params = (
|
||||
|
||||
@@ -548,6 +548,41 @@ async def test_generate_content_async(mock_acompletion, lite_llm_instance):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_generate_content_async_adds_fallback_user_message(
|
||||
mock_acompletion, lite_llm_instance
|
||||
):
|
||||
llm_request = LlmRequest(
|
||||
contents=[
|
||||
types.Content(
|
||||
role="user",
|
||||
parts=[],
|
||||
)
|
||||
]
|
||||
)
|
||||
|
||||
async for _ in lite_llm_instance.generate_content_async(llm_request):
|
||||
pass
|
||||
|
||||
mock_acompletion.assert_called_once()
|
||||
|
||||
_, kwargs = mock_acompletion.call_args
|
||||
user_messages = [
|
||||
message for message in kwargs["messages"] if message["role"] == "user"
|
||||
]
|
||||
assert any(
|
||||
message.get("content")
|
||||
== "Handle the requests as specified in the System Instruction."
|
||||
for message in user_messages
|
||||
)
|
||||
assert (
|
||||
sum(1 for content in llm_request.contents if content.role == "user") == 1
|
||||
)
|
||||
assert llm_request.contents[-1].parts[0].text == (
|
||||
"Handle the requests as specified in the System Instruction."
|
||||
)
|
||||
|
||||
|
||||
litellm_append_user_content_test_cases = [
|
||||
pytest.param(
|
||||
LlmRequest(
|
||||
|
||||
Reference in New Issue
Block a user