mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-20 22:24:01 +00:00
Merge pull request #12651 from ocraviotto/fix-gemini-400-when-no-user-msg
fix: ensure Gemini calls include a user message (fixes #9733)
This commit is contained in:
@@ -387,6 +387,19 @@ def _gemini_convert_messages_with_history( # noqa: PLR0915
|
||||
)
|
||||
if len(tool_call_responses) > 0:
|
||||
contents.append(ContentType(parts=tool_call_responses))
|
||||
|
||||
if len(contents) == 0:
|
||||
verbose_logger.warning(
|
||||
"""
|
||||
No contents in messages. Contents are required. See
|
||||
https://cloud.google.com/vertex-ai/docs/reference/rest/v1/projects.locations.publishers.models/generateContent#request-body.
|
||||
If the original request did not comply to OpenAI API requirements it should have failed by now,
|
||||
but LiteLLM does not check for missing messages.
|
||||
Setting an empty content to prevent an 400 error.
|
||||
Relevant Issue - https://github.com/BerriAI/litellm/issues/9733
|
||||
"""
|
||||
)
|
||||
contents.append(ContentType(role="user", parts=[PartType(text=" ")]))
|
||||
return contents
|
||||
except Exception as e:
|
||||
raise e
|
||||
@@ -505,19 +518,21 @@ def sync_transform_request_body(
|
||||
context_caching_endpoints = ContextCachingEndpoints()
|
||||
|
||||
if gemini_api_key is not None:
|
||||
messages, optional_params, cached_content = (
|
||||
context_caching_endpoints.check_and_create_cache(
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
api_key=gemini_api_key,
|
||||
api_base=api_base,
|
||||
model=model,
|
||||
client=client,
|
||||
timeout=timeout,
|
||||
extra_headers=extra_headers,
|
||||
cached_content=optional_params.pop("cached_content", None),
|
||||
logging_obj=logging_obj,
|
||||
)
|
||||
(
|
||||
messages,
|
||||
optional_params,
|
||||
cached_content,
|
||||
) = context_caching_endpoints.check_and_create_cache(
|
||||
messages=messages,
|
||||
optional_params=optional_params,
|
||||
api_key=gemini_api_key,
|
||||
api_base=api_base,
|
||||
model=model,
|
||||
client=client,
|
||||
timeout=timeout,
|
||||
extra_headers=extra_headers,
|
||||
cached_content=optional_params.pop("cached_content", None),
|
||||
logging_obj=logging_obj,
|
||||
)
|
||||
else: # [TODO] implement context caching for gemini as well
|
||||
cached_content = optional_params.pop("cached_content", None)
|
||||
|
||||
@@ -7,7 +7,7 @@ import pytest
|
||||
|
||||
sys.path.insert(0, os.path.abspath("../.."))
|
||||
|
||||
from typing import Union
|
||||
from typing import Union, List
|
||||
|
||||
# from litellm.litellm_core_utils.prompt_templates.factory import prompt_factory
|
||||
import litellm
|
||||
@@ -28,6 +28,7 @@ from litellm.litellm_core_utils.prompt_templates.common_utils import (
|
||||
from litellm.llms.vertex_ai.gemini.transformation import (
|
||||
_gemini_convert_messages_with_history,
|
||||
)
|
||||
from litellm.types.llms.openai import AllMessageValues
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
||||
|
||||
@@ -472,6 +473,20 @@ def test_vertex_only_image_user_message():
|
||||
)
|
||||
|
||||
|
||||
def test_no_messages_yields_user_text():
|
||||
"""
|
||||
Test that contents are not empty and have text when called without messages
|
||||
This is to support blha blah
|
||||
"""
|
||||
messages: List[AllMessageValues] = []
|
||||
|
||||
contents = _gemini_convert_messages_with_history(messages=messages)
|
||||
|
||||
expected_output = [{"role": "user", "parts": [{"text": " "}]}]
|
||||
|
||||
assert contents == expected_output
|
||||
|
||||
|
||||
def test_convert_url():
|
||||
convert_url_to_base64("https://picsum.photos/id/237/200/300")
|
||||
|
||||
@@ -630,7 +645,6 @@ def test_azure_tool_call_invoke_helper():
|
||||
def test_ensure_alternating_roles(
|
||||
messages, expected_messages, user_continue_message, assistant_continue_message
|
||||
):
|
||||
|
||||
messages = get_completion_messages(
|
||||
messages=messages,
|
||||
assistant_continue_message=assistant_continue_message,
|
||||
@@ -651,7 +665,7 @@ def test_alternating_roles_e2e():
|
||||
http_handler = HTTPHandler()
|
||||
|
||||
with patch.object(http_handler, "post", new=MagicMock()) as mock_post:
|
||||
try:
|
||||
try:
|
||||
response = litellm.completion(
|
||||
**{
|
||||
"model": "databricks/databricks-meta-llama-3-1-70b-instruct",
|
||||
@@ -663,7 +677,10 @@ def test_alternating_roles_e2e():
|
||||
},
|
||||
{"role": "user", "content": "What is Databricks?"},
|
||||
{"role": "user", "content": "What is Azure?"},
|
||||
{"role": "assistant", "content": "I don't know anyything, do you?"},
|
||||
{
|
||||
"role": "assistant",
|
||||
"content": "I don't know anyything, do you?",
|
||||
},
|
||||
{"role": "assistant", "content": "I can't repeat sentences."},
|
||||
],
|
||||
"user_continue_message": {
|
||||
@@ -712,7 +729,7 @@ def test_alternating_roles_e2e():
|
||||
"role": "user",
|
||||
"content": "Ok",
|
||||
},
|
||||
]
|
||||
],
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user