@@ -949,54 +949,128 @@ async def test_send_history_filters_various_audio_mime_types(
949949
950950@pytest .mark .asyncio
951951async def test_send_history_gemini_31_turn_complete (mock_gemini_session ):
952- """Verify Gemini 3.1 Live history seeding explicitly appends turn_complete=True ."""
952+ """Verify Gemini 3.1 Live history seeding sets turn_complete based on history[-1].role == 'user' ."""
953953 conn = GeminiLlmConnection (
954954 mock_gemini_session ,
955955 api_backend = GoogleLLMVariant .GEMINI_API ,
956956 model_version = 'gemini-3.1-flash-live-preview' ,
957957 )
958958 mock_gemini_session .send_client_content = mock .AsyncMock ()
959959
960- mock_contents = [
960+ # Last turn is model -> turn_complete=False
961+ mock_contents_model = [
961962 types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
962963 types .Content (role = 'model' , parts = [types .Part .from_text (text = 'hello' )]),
963964 ]
964- await conn .send_history (mock_contents )
965+ await conn .send_history (mock_contents_model )
965966
966967 mock_gemini_session .send_client_content .assert_called_once_with (
967- turns = mock_contents ,
968+ turns = mock_contents_model ,
969+ turn_complete = False ,
970+ )
971+
972+ # Last turn is user -> turn_complete=True
973+ mock_gemini_session .send_client_content .reset_mock ()
974+ mock_contents_user = [
975+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
976+ ]
977+ await conn .send_history (mock_contents_user )
978+
979+ mock_gemini_session .send_client_content .assert_called_once_with (
980+ turns = mock_contents_user ,
968981 turn_complete = True ,
969982 )
970983
971984
972985@pytest .mark .asyncio
973- async def test_send_history_collapse_vertex_ai (mock_gemini_session ):
974- """Verify history prompt collapse when seeding Gemini 3.1 Live on Vertex AI backend."""
986+ async def test_send_history_vertex_ai_no_collapse (mock_gemini_session ):
987+ """Verify history is sent without collapsing on Vertex AI backend."""
975988 conn = GeminiLlmConnection (
976989 mock_gemini_session ,
977990 api_backend = GoogleLLMVariant .VERTEX_AI ,
978991 model_version = 'gemini-3.1-flash-live-preview' ,
979992 )
980993 mock_gemini_session .send_client_content = mock .AsyncMock ()
981994
982- mock_contents = [
995+ # Last turn is model -> turn_complete=False
996+ mock_contents_model = [
983997 types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
984998 types .Content (role = 'model' , parts = [types .Part .from_text (text = 'hello' )]),
985999 ]
986- await conn .send_history (mock_contents )
1000+ await conn .send_history (mock_contents_model )
9871001
988- assert mock_gemini_session .send_client_content .call_count == 1
989- called_turns = mock_gemini_session .send_client_content .call_args .kwargs [
990- 'turns'
1002+ mock_gemini_session .send_client_content .assert_called_once_with (
1003+ turns = mock_contents_model ,
1004+ turn_complete = False ,
1005+ )
1006+
1007+ # Last turn is user -> turn_complete=True
1008+ mock_gemini_session .send_client_content .reset_mock ()
1009+ mock_contents_user = [
1010+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
1011+ types .Content (role = 'model' , parts = [types .Part .from_text (text = 'hello' )]),
1012+ types .Content (
1013+ role = 'user' , parts = [types .Part .from_text (text = 'how are you?' )]
1014+ ),
9911015 ]
992- assert len (called_turns ) == 1
993- assert called_turns [0 ].role == 'user'
994- assert 'Previous conversation history:' in called_turns [0 ].parts [0 ].text
995- assert '[user]: hi' in called_turns [0 ].parts [0 ].text
996- assert '[model]: hello' in called_turns [0 ].parts [0 ].text
997- assert (
998- mock_gemini_session .send_client_content .call_args .kwargs ['turn_complete' ]
999- is True
1016+ await conn .send_history (mock_contents_user )
1017+
1018+ mock_gemini_session .send_client_content .assert_called_once_with (
1019+ turns = mock_contents_user ,
1020+ turn_complete = True ,
1021+ )
1022+
1023+
1024+ @pytest .mark .asyncio
1025+ async def test_send_history_turn_complete_determined_by_filtered_content (
1026+ mock_gemini_session ,
1027+ ):
1028+ """Verify turn_complete is determined by the last element of filtered content instead of unfiltered history."""
1029+ conn = GeminiLlmConnection (
1030+ mock_gemini_session ,
1031+ api_backend = GoogleLLMVariant .GEMINI_API ,
1032+ model_version = 'gemini-3.1-flash-live-preview' ,
1033+ )
1034+ mock_gemini_session .send_client_content = mock .AsyncMock ()
1035+
1036+ # Scenario: Last turn in history is a user audio turn (gets filtered out).
1037+ # The remaining last turn is model's turn -> turn_complete should be False.
1038+ audio_part = types .Part (
1039+ inline_data = types .Blob (data = b'\x00 \xFF ' , mime_type = 'audio/pcm' )
1040+ )
1041+ history_with_final_audio_user_turn = [
1042+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
1043+ types .Content (role = 'model' , parts = [types .Part .from_text (text = 'hello' )]),
1044+ types .Content (role = 'user' , parts = [audio_part ]),
1045+ ]
1046+
1047+ await conn .send_history (history_with_final_audio_user_turn )
1048+
1049+ expected_contents = [
1050+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
1051+ types .Content (role = 'model' , parts = [types .Part .from_text (text = 'hello' )]),
1052+ ]
1053+ mock_gemini_session .send_client_content .assert_called_once_with (
1054+ turns = expected_contents ,
1055+ turn_complete = False ,
1056+ )
1057+
1058+ # Scenario: Last turn in history is a model audio turn (gets filtered out).
1059+ # The remaining last turn is user's turn -> turn_complete should be True.
1060+ mock_gemini_session .send_client_content .reset_mock ()
1061+ history_with_final_audio_model_turn = [
1062+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
1063+ types .Content (role = 'model' , parts = [audio_part ]),
1064+ ]
1065+
1066+ await conn .send_history (history_with_final_audio_model_turn )
1067+
1068+ expected_contents = [
1069+ types .Content (role = 'user' , parts = [types .Part .from_text (text = 'hi' )]),
1070+ ]
1071+ mock_gemini_session .send_client_content .assert_called_once_with (
1072+ turns = expected_contents ,
1073+ turn_complete = True ,
10001074 )
10011075
10021076
0 commit comments