@@ -109,3 +109,73 @@ async def test_close(gemini_connection, mock_gemini_session):
109109 await gemini_connection .close ()
110110
111111 mock_gemini_session .close .assert_called_once ()
112+
113+
114+ @pytest .mark .asyncio
115+ async def test_receive_usage_metadata_and_server_content (
116+ gemini_connection , mock_gemini_session
117+ ):
118+ """Test receive with usage metadata and server content in one message."""
119+ usage_metadata = types .UsageMetadata (
120+ prompt_token_count = 10 ,
121+ cached_content_token_count = 5 ,
122+ response_token_count = 20 ,
123+ total_token_count = 35 ,
124+ thoughts_token_count = 2 ,
125+ prompt_tokens_details = [
126+ types .ModalityTokenCount (modality = 'text' , token_count = 10 )
127+ ],
128+ cache_tokens_details = [
129+ types .ModalityTokenCount (modality = 'text' , token_count = 5 )
130+ ],
131+ response_tokens_details = [
132+ types .ModalityTokenCount (modality = 'text' , token_count = 20 )
133+ ],
134+ )
135+ mock_content = types .Content (
136+ role = 'model' , parts = [types .Part .from_text (text = 'response text' )]
137+ )
138+ mock_server_content = mock .Mock ()
139+ mock_server_content .model_turn = mock_content
140+ mock_server_content .interrupted = False
141+ mock_server_content .input_transcription = None
142+ mock_server_content .output_transcription = None
143+ mock_server_content .turn_complete = False
144+
145+ mock_message = mock .AsyncMock ()
146+ mock_message .usage_metadata = usage_metadata
147+ mock_message .server_content = mock_server_content
148+ mock_message .tool_call = None
149+ mock_message .session_resumption_update = None
150+
151+ async def mock_receive_generator ():
152+ yield mock_message
153+
154+ receive_mock = mock .Mock (return_value = mock_receive_generator ())
155+ mock_gemini_session .receive = receive_mock
156+
157+ responses = [resp async for resp in gemini_connection .receive ()]
158+
159+ assert responses
160+
161+ usage_response = next ((r for r in responses if r .usage_metadata ), None )
162+ assert usage_response is not None
163+ content_response = next ((r for r in responses if r .content ), None )
164+ assert content_response is not None
165+
166+ expected_usage = types .GenerateContentResponseUsageMetadata (
167+ prompt_token_count = 10 ,
168+ cached_content_token_count = 5 ,
169+ candidates_token_count = None ,
170+ total_token_count = 35 ,
171+ thoughts_token_count = 2 ,
172+ prompt_tokens_details = [
173+ types .ModalityTokenCount (modality = 'text' , token_count = 10 )
174+ ],
175+ cache_tokens_details = [
176+ types .ModalityTokenCount (modality = 'text' , token_count = 5 )
177+ ],
178+ candidates_tokens_details = None ,
179+ )
180+ assert usage_response .usage_metadata == expected_usage
181+ assert content_response .content == mock_content
0 commit comments