Skip to content

Commit 6a0f5b7

Browse files
committed
feat(live): update from StreamTranslationConfig to TranslationConfig
1 parent b9a4539 commit 6a0f5b7

8 files changed

Lines changed: 70 additions & 12 deletions

File tree

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ dependencies = [
3838
"click>=8.1.8,<9",
3939
"fastapi>=0.133,<1",
4040
"google-auth[pyopenssl]>=2.47",
41-
"google-genai>=2.4,<3",
41+
"google-genai>=2.8,<3",
4242
"graphviz>=0.20.2,<1",
4343
"httpx>=0.27,<1",
4444
"jsonschema>=4.23,<5",

src/google/adk/agents/run_config.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,12 @@ class RunConfig(BaseModel):
239239
realtime_input_config: Optional[types.RealtimeInputConfig] = None
240240
"""Realtime input config for live agents with audio input from user."""
241241

242-
translation_config: Optional[types.StreamTranslationConfig] = None
243-
"""Configures real-time speech-to-speech translation for live agents."""
242+
translation_config: Optional[types.TranslationConfig] = None
243+
"""Configures real-time speech-to-speech translation.
244+
245+
Only supported by translation models such as
246+
`gemini-3.5-live-translate-preview`.
247+
"""
244248

245249
enable_affective_dialog: Optional[bool] = None
246250
"""If enabled, the model will detect emotions and adapt its responses accordingly."""

src/google/adk/flows/llm_flows/basic.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ def _build_basic_request(
8383
llm_request.live_connect_config.realtime_input_config = (
8484
invocation_context.run_config.realtime_input_config
8585
)
86-
llm_request.live_connect_config.stream_translation_config = (
86+
llm_request.live_connect_config.translation_config = (
8787
invocation_context.run_config.translation_config
8888
)
8989
active_model_name = (

src/google/adk/models/gemini_llm_connection.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,9 @@ def __init__(
5353
self._is_gemini_3_1_flash_live = model_name_utils.is_gemini_3_1_flash_live(
5454
model_version
5555
)
56+
self._is_gemini_3_5_live_translate = (
57+
model_name_utils.is_gemini_3_5_live_translate(model_version)
58+
)
5659

5760
async def send_history(self, history: list[types.Content]):
5861
"""Sends the conversation history to the gemini model.
@@ -160,7 +163,7 @@ async def send_realtime(self, input: RealtimeInput):
160163
if isinstance(input, types.Blob):
161164
# The blob is binary and is very large. So let's not log it.
162165
logger.debug('Sending LLM Blob.')
163-
if self._is_gemini_3_1_flash_live:
166+
if self._is_gemini_3_1_flash_live or self._is_gemini_3_5_live_translate:
164167
if input.mime_type and input.mime_type.startswith('audio/'):
165168
await self._gemini_session.send_realtime_input(audio=input)
166169
elif input.mime_type and input.mime_type.startswith('image/'):

src/google/adk/utils/model_name_utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,3 +174,18 @@ def is_gemini_3_1_flash_live(model_string: Optional[str]) -> bool:
174174
return False
175175
model_name = extract_model_name(model_string)
176176
return model_name.startswith('gemini-3.1-flash-live')
177+
178+
179+
def is_gemini_3_5_live_translate(model_string: Optional[str]) -> bool:
180+
"""Check if the model is a Gemini 3.5 Live Translate model.
181+
182+
Args:
183+
model_string: The model name
184+
185+
Returns:
186+
True if it's a Gemini 3.5 Live Translate model, False otherwise
187+
"""
188+
if not model_string:
189+
return False
190+
model_name = extract_model_name(model_string)
191+
return model_name.startswith('gemini-3.5-live-translate')

tests/unittests/flows/llm_flows/test_basic_processor.py

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ async def test_sets_translation_config(self):
264264
)
265265
invocation_context = await _create_invocation_context(agent)
266266
invocation_context.run_config = RunConfig(
267-
translation_config=types.StreamTranslationConfig(
267+
translation_config=types.TranslationConfig(
268268
target_language_code='pl',
269269
echo_target_language=True,
270270
),
@@ -275,11 +275,9 @@ async def test_sets_translation_config(self):
275275
async for _ in processor.run_async(invocation_context, llm_request):
276276
pass
277277

278-
stream_translation_config = (
279-
llm_request.live_connect_config.stream_translation_config
280-
)
281-
assert stream_translation_config.target_language_code == 'pl'
282-
assert stream_translation_config.echo_target_language is True
278+
translation_config = llm_request.live_connect_config.translation_config
279+
assert translation_config.target_language_code == 'pl'
280+
assert translation_config.echo_target_language is True
283281

284282
@pytest.mark.asyncio
285283
async def test_translation_config_defaults_to_none(self):
@@ -295,4 +293,4 @@ async def test_translation_config_defaults_to_none(self):
295293
async for _ in processor.run_async(invocation_context, llm_request):
296294
pass
297295

298-
assert llm_request.live_connect_config.stream_translation_config is None
296+
assert llm_request.live_connect_config.translation_config is None

tests/unittests/models/test_gemini_llm_connection.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,24 @@ async def test_send_realtime_default_behavior(
7171
mock_gemini_session.send.assert_not_called()
7272

7373

74+
@pytest.mark.asyncio
75+
async def test_send_realtime_audio_uses_audio_channel_for_live_translate(
76+
mock_gemini_session, test_blob
77+
):
78+
"""Live Translate models stream audio via the dedicated `audio=` channel."""
79+
connection = GeminiLlmConnection(
80+
mock_gemini_session,
81+
api_backend=GoogleLLMVariant.GEMINI_API,
82+
model_version='gemini-3.5-live-translate-preview',
83+
)
84+
85+
await connection.send_realtime(test_blob)
86+
87+
mock_gemini_session.send_realtime_input.assert_called_once_with(
88+
audio=test_blob
89+
)
90+
91+
7492
@pytest.mark.asyncio
7593
async def test_send_history(gemini_connection, mock_gemini_session):
7694
"""Test send_history method."""

tests/unittests/utils/test_model_name_utils.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
from google.adk.utils.model_name_utils import extract_model_name
1818
from google.adk.utils.model_name_utils import is_gemini_1_model
1919
from google.adk.utils.model_name_utils import is_gemini_3_1_flash_live
20+
from google.adk.utils.model_name_utils import is_gemini_3_5_live_translate
2021
from google.adk.utils.model_name_utils import is_gemini_eap_or_2_or_above
2122
from google.adk.utils.model_name_utils import is_gemini_model
2223
from google.adk.utils.model_name_utils import is_gemini_model_id_check_disabled
@@ -366,3 +367,22 @@ def test_is_gemini_3_1_flash_live_edge_cases(self):
366367
"""Test edge cases."""
367368
assert is_gemini_3_1_flash_live(None) is False
368369
assert is_gemini_3_1_flash_live('') is False
370+
371+
372+
class TestIsGemini35LiveTranslate:
373+
"""Test the is_gemini_3_5_live_translate function."""
374+
375+
def test_is_gemini_3_5_live_translate_simple_name(self):
376+
"""Test with simple model name format."""
377+
assert is_gemini_3_5_live_translate('gemini-3.5-live-translate') is True
378+
assert is_gemini_3_5_live_translate('gemini-3.5-flash-live') is False
379+
380+
def test_is_gemini_3_5_live_translate_path_based_name(self):
381+
"""Test with path-based format (Vertex AI etc.)."""
382+
vertex_path = 'projects/123/locations/us-central1/publishers/google/models/gemini-3.5-live-translate-preview'
383+
assert is_gemini_3_5_live_translate(vertex_path) is True
384+
385+
def test_is_gemini_3_5_live_translate_edge_cases(self):
386+
"""Test edge cases."""
387+
assert is_gemini_3_5_live_translate(None) is False
388+
assert is_gemini_3_5_live_translate('') is False

0 commit comments

Comments
 (0)