From e8864b1dd698461616789757d4d18cce663cf846 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Sun, 7 Dec 2025 22:58:33 +0100 Subject: [PATCH 01/10] add fix to ensure finished transcript has whitespaces --- .../adk/models/gemini_llm_connection.py | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/google/adk/models/gemini_llm_connection.py b/src/google/adk/models/gemini_llm_connection.py index 55d4b62e96..ddf543a230 100644 --- a/src/google/adk/models/gemini_llm_connection.py +++ b/src/google/adk/models/gemini_llm_connection.py @@ -181,13 +181,16 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: # generation_complete, causing transcription to appear after # tool_call in the session log. if message.server_content.input_transcription: - if message.server_content.input_transcription.text: - self._input_transcription_text += ( - message.server_content.input_transcription.text + if ( + new_input_transcription_chunk := message.server_content.input_transcription.text + ): + self._input_transcription_text = ( + f'{self._input_transcription_text} {new_input_transcription_chunk.strip()}' + .strip() ) yield LlmResponse( input_transcription=types.Transcription( - text=message.server_content.input_transcription.text, + text=new_input_transcription_chunk, finished=False, ), partial=True, @@ -204,13 +207,16 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: ) self._input_transcription_text = '' if message.server_content.output_transcription: - if message.server_content.output_transcription.text: - self._output_transcription_text += ( - message.server_content.output_transcription.text + if ( + new_output_transcription_chunk := message.server_content.output_transcription.text + ): + self._output_transcription_text = ( + f'{self._output_transcription_text} {new_output_transcription_chunk.strip()}' + .strip() ) yield LlmResponse( output_transcription=types.Transcription( - text=message.server_content.output_transcription.text, + text=new_output_transcription_chunk, finished=False, ), partial=True, From 5901190c0fe206a6ed640f1e2bb3cd10ddc0532c Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Sun, 7 Dec 2025 23:00:19 +0100 Subject: [PATCH 02/10] add unittest for final transcription whitespaces appearance --- .../models/test_gemini_llm_connection.py | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/tests/unittests/models/test_gemini_llm_connection.py b/tests/unittests/models/test_gemini_llm_connection.py index 190007603c..5d93d7edb5 100644 --- a/tests/unittests/models/test_gemini_llm_connection.py +++ b/tests/unittests/models/test_gemini_llm_connection.py @@ -593,3 +593,101 @@ async def mock_receive_generator(): assert responses[2].output_transcription.text == 'How can I help?' assert responses[2].output_transcription.finished is True assert responses[2].partial is False + + +@pytest.mark.asyncio +@pytest.mark.parametrize('tx_direction', ['input', 'output']) +@pytest.mark.parametrize( + 'fragments', + [ + ('Hello', 'world'), + ('Hello', ' world'), + ('Hello ', 'world'), + ], +) +async def test_receive_final_transcription_space_between_fragments( + gemini_connection, mock_gemini_session, tx_direction, fragments +): + """Test receive final transcription fragments are joined with a space between words.""" + fragment1, fragment2 = fragments + + message1 = mock.Mock() + message1.usage_metadata = None + message1.server_content = mock.Mock() + message1.server_content.model_turn = None + message1.server_content.interrupted = False + message1.server_content.turn_complete = False + message1.server_content.generation_complete = False + message1.tool_call = None + message1.session_resumption_update = None + message1.server_content.input_transcription = ( + types.Transcription(text=fragment1, finished=False) + if tx_direction == 'input' + else None + ) + message1.server_content.output_transcription = ( + types.Transcription(text=fragment1, finished=False) + if tx_direction == 'output' + else None + ) + + message2 = mock.Mock() + message2.usage_metadata = None + message2.server_content = mock.Mock() + message2.server_content.model_turn = None + message2.server_content.interrupted = False + message2.server_content.turn_complete = False + message2.server_content.generation_complete = False + message2.tool_call = None + message2.session_resumption_update = None + message2.server_content.input_transcription = ( + types.Transcription(text=fragment2, finished=False) + if tx_direction == 'input' + else None + ) + message2.server_content.output_transcription = ( + types.Transcription(text=fragment2, finished=False) + if tx_direction == 'output' + else None + ) + + message3 = mock.Mock() + message3.usage_metadata = None + message3.server_content = mock.Mock() + message3.server_content.model_turn = None + message3.server_content.interrupted = False + message3.server_content.turn_complete = False + message3.server_content.generation_complete = False + message3.tool_call = None + message3.session_resumption_update = None + message3.server_content.input_transcription = ( + types.Transcription(text=None, finished=True) + if tx_direction == 'input' + else None + ) + message3.server_content.output_transcription = ( + types.Transcription(text=None, finished=True) + if tx_direction == 'output' + else None + ) + + async def mock_receive_generator(): + yield message1 + yield message2 + yield message3 + + receive_mock = mock.Mock(return_value=mock_receive_generator()) + mock_gemini_session.receive = receive_mock + + responses = [resp async for resp in gemini_connection.receive()] + + # find the finished transcription response + attr_name = f'{tx_direction}_transcription' + finished_resps = [ + r + for r in responses + if getattr(r, attr_name) and getattr(r, attr_name).finished + ] + assert finished_resps, 'Expected finished transcription response' + transcription = getattr(finished_resps[0], attr_name) + assert transcription.text == 'Hello world' From ce4e26914eaa172880516e52320b8b54d1782e7b Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Mon, 8 Dec 2025 23:51:49 +0100 Subject: [PATCH 03/10] update test cases --- tests/unittests/models/test_gemini_llm_connection.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/unittests/models/test_gemini_llm_connection.py b/tests/unittests/models/test_gemini_llm_connection.py index 5d93d7edb5..83144f8cac 100644 --- a/tests/unittests/models/test_gemini_llm_connection.py +++ b/tests/unittests/models/test_gemini_llm_connection.py @@ -600,9 +600,11 @@ async def mock_receive_generator(): @pytest.mark.parametrize( 'fragments', [ - ('Hello', 'world'), - ('Hello', ' world'), - ('Hello ', 'world'), + ('That', "'s great"), + ("That'", 's great'), + ("That's", 'great'), + ("That's", ' great'), + ("That's ", 'great'), ], ) async def test_receive_final_transcription_space_between_fragments( @@ -690,4 +692,4 @@ async def mock_receive_generator(): ] assert finished_resps, 'Expected finished transcription response' transcription = getattr(finished_resps[0], attr_name) - assert transcription.text == 'Hello world' + assert transcription.text == "That's great" From 38cc1c26a3f8b61ea7137923cb609be26d6c5d10 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Tue, 9 Dec 2025 00:01:05 +0100 Subject: [PATCH 04/10] fix fragments stich respecting punctuation marks --- .../adk/models/gemini_llm_connection.py | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/src/google/adk/models/gemini_llm_connection.py b/src/google/adk/models/gemini_llm_connection.py index ddf543a230..065b359f4c 100644 --- a/src/google/adk/models/gemini_llm_connection.py +++ b/src/google/adk/models/gemini_llm_connection.py @@ -30,6 +30,8 @@ RealtimeInput = Union[types.Blob, types.ActivityStart, types.ActivityEnd] from typing import TYPE_CHECKING +PUNCTUATION_CHARS = {'.', ',', '!', '?', ';', ':', "'", '"', ')', ']', '}', '(', '[', '{'} + if TYPE_CHECKING: from google.genai import live @@ -184,10 +186,20 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: if ( new_input_transcription_chunk := message.server_content.input_transcription.text ): - self._input_transcription_text = ( - f'{self._input_transcription_text} {new_input_transcription_chunk.strip()}' - .strip() + existing = self._input_transcription_text + # Insert a space only when there is existing text and neither + # the new chunk starts with punctuation nor the existing text + # ends with punctuation. + conditional_space = ( + ' ' + if existing + and not ( + new_input_transcription_chunk[0] in PUNCTUATION_CHARS + or existing[-1] in PUNCTUATION_CHARS + ) + else '' ) + self._input_transcription_text = f'{existing}{conditional_space}{new_input_transcription_chunk.strip()}'.strip() yield LlmResponse( input_transcription=types.Transcription( text=new_input_transcription_chunk, @@ -210,10 +222,20 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: if ( new_output_transcription_chunk := message.server_content.output_transcription.text ): - self._output_transcription_text = ( - f'{self._output_transcription_text} {new_output_transcription_chunk.strip()}' - .strip() + existing = self._output_transcription_text + # Insert a space only when there is existing text and neither + # the new chunk starts with punctuation nor the existing text + # ends with punctuation. + conditional_space = ( + ' ' + if existing + and not ( + new_output_transcription_chunk[0] in PUNCTUATION_CHARS + or existing[-1] in PUNCTUATION_CHARS + ) + else '' ) + self._output_transcription_text = f'{existing}{conditional_space}{new_output_transcription_chunk.strip()}'.strip() yield LlmResponse( output_transcription=types.Transcription( text=new_output_transcription_chunk, From c0f9d623e3519f97f5bc537bf7af0d60881d9b54 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Tue, 9 Dec 2025 00:30:56 +0100 Subject: [PATCH 05/10] add more test cases --- .../models/test_gemini_llm_connection.py | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tests/unittests/models/test_gemini_llm_connection.py b/tests/unittests/models/test_gemini_llm_connection.py index 83144f8cac..1a6460b3a5 100644 --- a/tests/unittests/models/test_gemini_llm_connection.py +++ b/tests/unittests/models/test_gemini_llm_connection.py @@ -600,18 +600,24 @@ async def mock_receive_generator(): @pytest.mark.parametrize( 'fragments', [ - ('That', "'s great"), - ("That'", 's great'), - ("That's", 'great'), - ("That's", ' great'), - ("That's ", 'great'), + ('That', "'s great", "That's great"), + ("That'", 's great', "That's great"), + ("That's", 'great', "That's great"), + ("That's", ' great', "That's great"), + ("That's ", 'great', "That's great"), + ("Great", '! Good to hear', 'Great! Good to hear'), + ("Great!", 'Good to hear', 'Great! Good to hear'), + ("Great! ", 'Good to hear', 'Great! Good to hear'), + ("Great! Good", 'to hear', 'Great! Good to hear'), + ("Great! Good ", 'to hear', 'Great! Good to hear'), + ("Great! Good", ' to hear', 'Great! Good to hear'), ], ) async def test_receive_final_transcription_space_between_fragments( gemini_connection, mock_gemini_session, tx_direction, fragments ): """Test receive final transcription fragments are joined with a space between words.""" - fragment1, fragment2 = fragments + fragment1, fragment2, expected = fragments message1 = mock.Mock() message1.usage_metadata = None @@ -692,4 +698,4 @@ async def mock_receive_generator(): ] assert finished_resps, 'Expected finished transcription response' transcription = getattr(finished_resps[0], attr_name) - assert transcription.text == "That's great" + assert transcription.text == expected From ed863a3e3a44248d23fd27e458f710c3ad1032c1 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Tue, 9 Dec 2025 00:31:11 +0100 Subject: [PATCH 06/10] update logic of conditional_space --- .../adk/models/gemini_llm_connection.py | 44 ++++++++++--------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/src/google/adk/models/gemini_llm_connection.py b/src/google/adk/models/gemini_llm_connection.py index 065b359f4c..da0b3cc895 100644 --- a/src/google/adk/models/gemini_llm_connection.py +++ b/src/google/adk/models/gemini_llm_connection.py @@ -30,7 +30,7 @@ RealtimeInput = Union[types.Blob, types.ActivityStart, types.ActivityEnd] from typing import TYPE_CHECKING -PUNCTUATION_CHARS = {'.', ',', '!', '?', ';', ':', "'", '"', ')', ']', '}', '(', '[', '{'} +PUNCTUATION_CHARS = {'.', '!', '?', ';', ':', "'"} if TYPE_CHECKING: from google.genai import live @@ -187,17 +187,18 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: new_input_transcription_chunk := message.server_content.input_transcription.text ): existing = self._input_transcription_text - # Insert a space only when there is existing text and neither - # the new chunk starts with punctuation nor the existing text - # ends with punctuation. + # Insert a space when joining fragments except when the new + # chunk starts with a punctuation character that should attach + # to the previous token, or the existing text ends with an + # apostrophe. conditional_space = ( - ' ' - if existing - and not ( - new_input_transcription_chunk[0] in PUNCTUATION_CHARS - or existing[-1] in PUNCTUATION_CHARS - ) - else '' + ' ' + if existing + and not ( + new_input_transcription_chunk[0] in PUNCTUATION_CHARS + or existing.endswith("'") + ) + else '' ) self._input_transcription_text = f'{existing}{conditional_space}{new_input_transcription_chunk.strip()}'.strip() yield LlmResponse( @@ -223,17 +224,18 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: new_output_transcription_chunk := message.server_content.output_transcription.text ): existing = self._output_transcription_text - # Insert a space only when there is existing text and neither - # the new chunk starts with punctuation nor the existing text - # ends with punctuation. + # Insert a space when joining fragments except when the new + # chunk starts with a punctuation character that should attach + # to the previous token, or the existing text ends with an + # apostrophe. conditional_space = ( - ' ' - if existing - and not ( - new_output_transcription_chunk[0] in PUNCTUATION_CHARS - or existing[-1] in PUNCTUATION_CHARS - ) - else '' + ' ' + if existing + and not ( + new_output_transcription_chunk[0] in PUNCTUATION_CHARS + or existing.endswith("'") + ) + else '' ) self._output_transcription_text = f'{existing}{conditional_space}{new_output_transcription_chunk.strip()}'.strip() yield LlmResponse( From ae99055cf859de4706d6462090331b239f519294 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Mon, 15 Dec 2025 22:38:30 +0100 Subject: [PATCH 07/10] move fragments joining logic to other file; handle plural form apostrophe --- .../adk/models/gemini_llm_connection.py | 34 ++-------- src/google/adk/utils/transcription_utils.py | 66 +++++++++++++++++++ 2 files changed, 72 insertions(+), 28 deletions(-) create mode 100644 src/google/adk/utils/transcription_utils.py diff --git a/src/google/adk/models/gemini_llm_connection.py b/src/google/adk/models/gemini_llm_connection.py index da0b3cc895..c228736847 100644 --- a/src/google/adk/models/gemini_llm_connection.py +++ b/src/google/adk/models/gemini_llm_connection.py @@ -16,11 +16,13 @@ import logging from typing import AsyncGenerator +from typing import TYPE_CHECKING from typing import Union from google.genai import types from ..utils.context_utils import Aclosing +from ..utils.transcription_utils import join_fragment from ..utils.variant_utils import GoogleLLMVariant from .base_llm_connection import BaseLlmConnection from .llm_response import LlmResponse @@ -28,9 +30,7 @@ logger = logging.getLogger('google_adk.' + __name__) RealtimeInput = Union[types.Blob, types.ActivityStart, types.ActivityEnd] -from typing import TYPE_CHECKING -PUNCTUATION_CHARS = {'.', '!', '?', ';', ':', "'"} if TYPE_CHECKING: from google.genai import live @@ -187,20 +187,9 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: new_input_transcription_chunk := message.server_content.input_transcription.text ): existing = self._input_transcription_text - # Insert a space when joining fragments except when the new - # chunk starts with a punctuation character that should attach - # to the previous token, or the existing text ends with an - # apostrophe. - conditional_space = ( - ' ' - if existing - and not ( - new_input_transcription_chunk[0] in PUNCTUATION_CHARS - or existing.endswith("'") - ) - else '' + self._input_transcription_text = join_fragment( + existing, new_input_transcription_chunk ) - self._input_transcription_text = f'{existing}{conditional_space}{new_input_transcription_chunk.strip()}'.strip() yield LlmResponse( input_transcription=types.Transcription( text=new_input_transcription_chunk, @@ -224,20 +213,9 @@ async def receive(self) -> AsyncGenerator[LlmResponse, None]: new_output_transcription_chunk := message.server_content.output_transcription.text ): existing = self._output_transcription_text - # Insert a space when joining fragments except when the new - # chunk starts with a punctuation character that should attach - # to the previous token, or the existing text ends with an - # apostrophe. - conditional_space = ( - ' ' - if existing - and not ( - new_output_transcription_chunk[0] in PUNCTUATION_CHARS - or existing.endswith("'") - ) - else '' + self._output_transcription_text = join_fragment( + existing, new_output_transcription_chunk ) - self._output_transcription_text = f'{existing}{conditional_space}{new_output_transcription_chunk.strip()}'.strip() yield LlmResponse( output_transcription=types.Transcription( text=new_output_transcription_chunk, diff --git a/src/google/adk/utils/transcription_utils.py b/src/google/adk/utils/transcription_utils.py new file mode 100644 index 0000000000..f4a9257932 --- /dev/null +++ b/src/google/adk/utils/transcription_utils.py @@ -0,0 +1,66 @@ +# Copyright 2025 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Utilities for transcription text handling.""" + +PUNCTUATION_CHARS = {'.', '!', '?', ';', ':', "'"} + + +def join_fragment(existing_tx: str, new_chunk: str) -> str: + """Join transcription fragments preserving proper spacing. + + Handles three special cases: + - Leading punctuation on the new chunk (attach without space). + - Leading apostrophe followed by 's' (contraction, attach without space). + - Leading apostrophe followed by other letters (plural possessive): + move apostrophe to end of existing and insert a space before remainder. + + Also avoids introducing double spaces when `existing` already ends + with whitespace. + """ + new_stripped = new_chunk.strip() + if not new_stripped: + return existing_tx + + # If the existing text ends with an apostrophe and the new fragment + # starts with 's' (continuation of a contraction), attach without + # a space: "That'" + "s great" -> "That's great". + if existing_tx.rstrip().endswith("'") and new_stripped[0].lower() == 's': + return existing_tx.rstrip() + new_stripped + + # Leading apostrophe handling when the new fragment itself starts + # with an apostrophe (e.g. "'s great" or "'job?"). + if new_stripped[0] == "'" and len(new_stripped) > 1: + remainder = new_stripped[1:] + # contraction like "'s": attach directly (That's) + if remainder[0].lower() == 's': + # If existing already ends with an apostrophe, don't add another. + if existing_tx.rstrip().endswith("'"): + return existing_tx.rstrip() + remainder + return existing_tx.rstrip() + "'" + remainder + # possessive like "'job": attach apostrophe to previous word, + # then add a space before the remainder (parents' job) + base = existing_tx.rstrip() + if not base.endswith("'"): + base = base + "'" + return base + ' ' + remainder + + # Leading punctuation attaches without a space (e.g. ? , !) + if new_stripped[0] in PUNCTUATION_CHARS: + return existing_tx.rstrip() + new_stripped + + # Default: add a space if existing doesn't already end with whitespace + if existing_tx and not existing_tx.endswith((' ', '\t', '\n')): + return existing_tx + ' ' + new_stripped + return existing_tx + new_stripped From 28365a035b1849373c2ce001401fd3766a5d2330 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Mon, 15 Dec 2025 22:38:43 +0100 Subject: [PATCH 08/10] add more test cases for test_receive_final_transcription_space_between_fragments --- .../models/test_gemini_llm_connection.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/unittests/models/test_gemini_llm_connection.py b/tests/unittests/models/test_gemini_llm_connection.py index 1a6460b3a5..82eaefce55 100644 --- a/tests/unittests/models/test_gemini_llm_connection.py +++ b/tests/unittests/models/test_gemini_llm_connection.py @@ -605,12 +605,17 @@ async def mock_receive_generator(): ("That's", 'great', "That's great"), ("That's", ' great', "That's great"), ("That's ", 'great', "That's great"), - ("Great", '! Good to hear', 'Great! Good to hear'), - ("Great!", 'Good to hear', 'Great! Good to hear'), - ("Great! ", 'Good to hear', 'Great! Good to hear'), - ("Great! Good", 'to hear', 'Great! Good to hear'), - ("Great! Good ", 'to hear', 'Great! Good to hear'), - ("Great! Good", ' to hear', 'Great! Good to hear'), + ('Great', '! Good to hear', 'Great! Good to hear'), + ('Great!', 'Good to hear', 'Great! Good to hear'), + ('Great! ', 'Good to hear', 'Great! Good to hear'), + ('Great! Good', 'to hear', 'Great! Good to hear'), + ('Great! Good ', 'to hear', 'Great! Good to hear'), + ('Great! Good', ' to hear', 'Great! Good to hear'), + ("Is that parents' job", '?', "Is that parents' job?"), + ("Is that parents' ", 'job?', "Is that parents' job?"), + ("Is that parents'", 'job?', "Is that parents' job?"), + ('Is that parents', "'job?", "Is that parents' job?"), + ('Is that parents', " 'job?", "Is that parents' job?"), ], ) async def test_receive_final_transcription_space_between_fragments( From e24f18a2c953a2a3c5b06d6a89bda6440c81ec48 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Mon, 15 Dec 2025 22:45:37 +0100 Subject: [PATCH 09/10] add simplified mock transcription message creator function --- .../models/test_gemini_llm_connection.py | 84 ++++++------------- 1 file changed, 25 insertions(+), 59 deletions(-) diff --git a/tests/unittests/models/test_gemini_llm_connection.py b/tests/unittests/models/test_gemini_llm_connection.py index 82eaefce55..66b78aa4e6 100644 --- a/tests/unittests/models/test_gemini_llm_connection.py +++ b/tests/unittests/models/test_gemini_llm_connection.py @@ -624,65 +624,31 @@ async def test_receive_final_transcription_space_between_fragments( """Test receive final transcription fragments are joined with a space between words.""" fragment1, fragment2, expected = fragments - message1 = mock.Mock() - message1.usage_metadata = None - message1.server_content = mock.Mock() - message1.server_content.model_turn = None - message1.server_content.interrupted = False - message1.server_content.turn_complete = False - message1.server_content.generation_complete = False - message1.tool_call = None - message1.session_resumption_update = None - message1.server_content.input_transcription = ( - types.Transcription(text=fragment1, finished=False) - if tx_direction == 'input' - else None - ) - message1.server_content.output_transcription = ( - types.Transcription(text=fragment1, finished=False) - if tx_direction == 'output' - else None - ) - - message2 = mock.Mock() - message2.usage_metadata = None - message2.server_content = mock.Mock() - message2.server_content.model_turn = None - message2.server_content.interrupted = False - message2.server_content.turn_complete = False - message2.server_content.generation_complete = False - message2.tool_call = None - message2.session_resumption_update = None - message2.server_content.input_transcription = ( - types.Transcription(text=fragment2, finished=False) - if tx_direction == 'input' - else None - ) - message2.server_content.output_transcription = ( - types.Transcription(text=fragment2, finished=False) - if tx_direction == 'output' - else None - ) - - message3 = mock.Mock() - message3.usage_metadata = None - message3.server_content = mock.Mock() - message3.server_content.model_turn = None - message3.server_content.interrupted = False - message3.server_content.turn_complete = False - message3.server_content.generation_complete = False - message3.tool_call = None - message3.session_resumption_update = None - message3.server_content.input_transcription = ( - types.Transcription(text=None, finished=True) - if tx_direction == 'input' - else None - ) - message3.server_content.output_transcription = ( - types.Transcription(text=None, finished=True) - if tx_direction == 'output' - else None - ) + def _create_mock_transcription_message( + text: str | None, finished: bool, direction: str + ) -> mock.Mock: + msg = mock.Mock() + msg.usage_metadata = None + msg.server_content = mock.Mock() + msg.server_content.model_turn = None + msg.server_content.interrupted = False + msg.server_content.turn_complete = False + msg.server_content.generation_complete = False + msg.tool_call = None + msg.session_resumption_update = None + + transcription = types.Transcription(text=text, finished=finished) + if direction == 'input': + msg.server_content.input_transcription = transcription + msg.server_content.output_transcription = None + else: + msg.server_content.input_transcription = None + msg.server_content.output_transcription = transcription + return msg + + message1 = _create_mock_transcription_message(fragment1, False, tx_direction) + message2 = _create_mock_transcription_message(fragment2, False, tx_direction) + message3 = _create_mock_transcription_message(None, True, tx_direction) async def mock_receive_generator(): yield message1 From 22f39a221d3372bfad973fc6003e9594aa687747 Mon Sep 17 00:00:00 2001 From: Krzysztof Czuszynski Date: Mon, 15 Dec 2025 22:46:14 +0100 Subject: [PATCH 10/10] autoformat changes --- contributing/samples/gepa/experiment.py | 1 - contributing/samples/gepa/run_experiment.py | 1 - 2 files changed, 2 deletions(-) diff --git a/contributing/samples/gepa/experiment.py b/contributing/samples/gepa/experiment.py index 2f5d03a772..f68b349d9c 100644 --- a/contributing/samples/gepa/experiment.py +++ b/contributing/samples/gepa/experiment.py @@ -43,7 +43,6 @@ from tau_bench.types import EnvRunResult from tau_bench.types import RunConfig import tau_bench_agent as tau_bench_agent_lib - import utils diff --git a/contributing/samples/gepa/run_experiment.py b/contributing/samples/gepa/run_experiment.py index cfd850b3a3..1bc4ee58c8 100644 --- a/contributing/samples/gepa/run_experiment.py +++ b/contributing/samples/gepa/run_experiment.py @@ -25,7 +25,6 @@ from absl import flags import experiment from google.genai import types - import utils _OUTPUT_DIR = flags.DEFINE_string(