diff --git a/homeassistant/components/google_generative_ai_conversation/conversation.py b/homeassistant/components/google_generative_ai_conversation/conversation.py index 5460f48f20e..7c19c5445a7 100644 --- a/homeassistant/components/google_generative_ai_conversation/conversation.py +++ b/homeassistant/components/google_generative_ai_conversation/conversation.py @@ -356,6 +356,15 @@ class GoogleGenerativeAIConversationEntity( messages.append(_convert_content(chat_content)) + # The SDK requires the first message to be a user message + # This is not the case if user used `start_conversation` + # Workaround from https://github.com/googleapis/python-genai/issues/529#issuecomment-2740964537 + if messages and messages[0].role != "user": + messages.insert( + 0, + Content(role="user", parts=[Part.from_text(text=" ")]), + ) + if tool_results: messages.append(_create_google_tool_response_content(tool_results)) generateContentConfig = GenerateContentConfig( diff --git a/tests/components/google_generative_ai_conversation/test_conversation.py b/tests/components/google_generative_ai_conversation/test_conversation.py index a2b238b9399..9c4ecc4f9a4 100644 --- a/tests/components/google_generative_ai_conversation/test_conversation.py +++ b/tests/components/google_generative_ai_conversation/test_conversation.py @@ -715,3 +715,48 @@ async def test_empty_content_in_chat_history( assert actual_history[0].parts[0].text == first_input assert actual_history[1].parts[0].text == " " + + +@pytest.mark.usefixtures("mock_init_component") +async def test_history_always_user_first_turn( + hass: HomeAssistant, + mock_config_entry: MockConfigEntry, + snapshot: SnapshotAssertion, +) -> None: + """Test that the user is always first in the chat history.""" + with ( + chat_session.async_get_chat_session(hass) as session, + async_get_chat_log(hass, session) as chat_log, + ): + chat_log.async_add_assistant_content_without_tools( + conversation.AssistantContent( + agent_id="conversation.google_generative_ai_conversation", + content="Garage door left open, do you want to close it?", + ) + ) + + with patch("google.genai.chats.AsyncChats.create") as mock_create: + mock_chat = AsyncMock() + mock_create.return_value.send_message = mock_chat + chat_response = Mock(prompt_feedback=None) + mock_chat.return_value = chat_response + chat_response.candidates = [Mock(content=Mock(parts=[]))] + + await conversation.async_converse( + hass, + "hello", + chat_log.conversation_id, + Context(), + agent_id="conversation.google_generative_ai_conversation", + ) + + _, kwargs = mock_create.call_args + actual_history = kwargs.get("history") + + assert actual_history[0].parts[0].text == " " + assert actual_history[0].role == "user" + assert ( + actual_history[1].parts[0].text + == "Garage door left open, do you want to close it?" + ) + assert actual_history[1].role == "model"