Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions lib/crewai/src/crewai/llms/providers/gemini/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
import re
from typing import Any, Literal, cast

from pydantic import BaseModel, Field, PrivateAttr, model_validator

from crewai.events.types.llm_events import LLMCallType
from crewai.llms.base_llm import BaseLLM, llm_call_context
from crewai.llms.hooks.base import BaseInterceptor
Expand All @@ -18,6 +16,7 @@
)
from crewai.utilities.pydantic_schema_utils import generate_model_description
from crewai.utilities.types import LLMMessage
from pydantic import BaseModel, Field, PrivateAttr, model_validator


try:
Expand Down Expand Up @@ -672,6 +671,14 @@ def _format_messages_for_gemini(
gemini_content = types.Content(role=gemini_role, parts=parts)
contents.append(gemini_content)

if contents and contents[-1].role == "model":
contents.append(
types.Content(
role="user",
parts=[types.Part.from_text(text="Please continue.")],
)
)

return contents, system_instruction

def _validate_and_emit_structured_output(
Expand Down
56 changes: 56 additions & 0 deletions lib/crewai/tests/llms/google/test_google.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from crewai.crew import Crew
from crewai.agent import Agent
from crewai.task import Task
from crewai.utilities.types import LLMMessage


@pytest.fixture(autouse=True)
Expand Down Expand Up @@ -500,6 +501,61 @@ def test_gemini_message_formatting():
assert formatted_contents[1].role == "model"


@pytest.mark.parametrize(
"assistant_message",
[
{"role": "assistant", "content": "Partial response"},
{
"role": "assistant",
"content": "",
"tool_calls": [
{
"id": "call_1",
"type": "function",
"function": {"name": "search", "arguments": "{}"},
}
],
},
],
)
def test_gemini_message_formatting_appends_user_after_model(
assistant_message: LLMMessage,
):
llm = LLM(model="google/gemini-2.0-flash-001")

formatted_contents, _ = llm._format_messages_for_gemini(
[
{"role": "user", "content": "Continue the task"},
assistant_message,
]
)

assert [content.role for content in formatted_contents] == [
"user",
"model",
"user",
]
model_parts = formatted_contents[1].parts
if assistant_message.get("tool_calls"):
assert model_parts[0].function_call.name == "search"
assert model_parts[0].function_call.args == {}
else:
assert model_parts[0].text == "Partial response"
assert formatted_contents[-1].parts[0].text == "Please continue."


def test_gemini_message_formatting_preserves_user_ending():
llm = LLM(model="google/gemini-2.0-flash-001")

formatted_contents, _ = llm._format_messages_for_gemini(
[{"role": "user", "content": "Hello"}]
)

assert len(formatted_contents) == 1
assert formatted_contents[-1].role == "user"
assert formatted_contents[-1].parts[0].text == "Hello"


def test_gemini_streaming_parameter():
"""
Test that streaming parameter is properly handled
Expand Down