google-genai 1.9.0__py3-none-any.whl → 1.10.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
google/genai/live.py CHANGED
@@ -13,14 +13,14 @@
13
13
  # limitations under the License.
14
14
  #
15
15
 
16
- """Live client. The live module is experimental."""
16
+ """[Preview] Live API client."""
17
17
 
18
18
  import asyncio
19
19
  import base64
20
20
  import contextlib
21
21
  import json
22
22
  import logging
23
- from typing import Any, AsyncIterator, Dict, Optional, Sequence, Union, get_args
23
+ from typing import Any, AsyncIterator, Dict, Optional, Sequence, Union, cast, get_args
24
24
  import warnings
25
25
 
26
26
  import google.auth
@@ -109,6 +109,13 @@ def _ToolResponse_to_vertex(
109
109
  tool_response = from_object.model_dump(exclude_none=True, mode='json')
110
110
  return tool_response
111
111
 
112
+ def _AudioTranscriptionConfig_to_mldev(
113
+ api_client: BaseApiClient,
114
+ from_object: types.AudioTranscriptionConfig,
115
+ ) -> dict:
116
+ audio_transcription: dict[str, Any] = {}
117
+ return audio_transcription
118
+
112
119
 
113
120
  def _AudioTranscriptionConfig_to_vertex(
114
121
  api_client: BaseApiClient,
@@ -119,7 +126,7 @@ def _AudioTranscriptionConfig_to_vertex(
119
126
 
120
127
 
121
128
  class AsyncSession:
122
- """AsyncSession. The live module is experimental."""
129
+ """[Preview] AsyncSession."""
123
130
 
124
131
  def __init__(
125
132
  self, api_client: client.BaseApiClient, websocket: ClientConnection
@@ -143,7 +150,12 @@ class AsyncSession:
143
150
  ] = None,
144
151
  end_of_turn: Optional[bool] = False,
145
152
  ):
146
- """Send input to the model.
153
+ """[Deprecated] Send input to the model.
154
+
155
+ > **Warning**: This method is deprecated and will be removed in a future
156
+ version (not before Q3 2025). Please use one of the more specific methods:
157
+ `send_client_content`, `send_realtime_input`, or `send_tool_response`
158
+ instead.
147
159
 
148
160
  The method will send the input request to the server.
149
161
 
@@ -162,6 +174,14 @@ class AsyncSession:
162
174
  async for message in session.receive():
163
175
  print(message)
164
176
  """
177
+ warnings.warn(
178
+ 'The `session.send` method is deprecated and will be removed in a '
179
+ 'future version (not before Q3 2025).\n'
180
+ 'Please use one of the more specific methods: `send_client_content`, '
181
+ '`send_realtime_input`, or `send_tool_response` instead.',
182
+ DeprecationWarning,
183
+ stacklevel=2,
184
+ )
165
185
  client_message = self._parse_client_message(input, end_of_turn)
166
186
  await self._ws.send(json.dumps(client_message))
167
187
 
@@ -375,8 +395,6 @@ class AsyncSession:
375
395
  is function call, user must call `send` with the function response to
376
396
  continue the turn.
377
397
 
378
- The live module is experimental.
379
-
380
398
  Yields:
381
399
  The model responses from the server.
382
400
 
@@ -401,15 +419,18 @@ class AsyncSession:
401
419
  async def start_stream(
402
420
  self, *, stream: AsyncIterator[bytes], mime_type: str
403
421
  ) -> AsyncIterator[types.LiveServerMessage]:
404
- """start a live session from a data stream.
422
+ """[Deprecated] Start a live session from a data stream.
423
+
424
+ > **Warning**: This method is deprecated and will be removed in a future
425
+ version (not before Q2 2025). Please use one of the more specific methods:
426
+ `send_client_content`, `send_realtime_input`, or `send_tool_response`
427
+ instead.
405
428
 
406
429
  The interaction terminates when the input stream is complete.
407
430
  This method will start two async tasks. One task will be used to send the
408
431
  input stream to the model and the other task will be used to receive the
409
432
  responses from the model.
410
433
 
411
- The live module is experimental.
412
-
413
434
  Args:
414
435
  stream: An iterator that yields the model response.
415
436
  mime_type: The MIME type of the data in the stream.
@@ -432,6 +453,13 @@ class AsyncSession:
432
453
  mime_type = 'audio/pcm'):
433
454
  play_audio_chunk(audio.data)
434
455
  """
456
+ warnings.warn(
457
+ 'Setting `AsyncSession.start_stream` is deprecated, '
458
+ 'and will be removed in a future release (not before Q3 2025). '
459
+ 'Please use the `receive`, and `send_realtime_input`, methods instead.',
460
+ DeprecationWarning,
461
+ stacklevel=4,
462
+ )
435
463
  stop_event = asyncio.Event()
436
464
  # Start the send loop. When stream is complete stop_event is set.
437
465
  asyncio.create_task(self._send_loop(stream, mime_type, stop_event))
@@ -465,7 +493,7 @@ class AsyncSession:
465
493
  try:
466
494
  raw_response = await self._ws.recv(decode=False)
467
495
  except TypeError:
468
- raw_response = await self._ws.recv()
496
+ raw_response = await self._ws.recv() # type: ignore[assignment]
469
497
  if raw_response:
470
498
  try:
471
499
  response = json.loads(raw_response)
@@ -473,6 +501,7 @@ class AsyncSession:
473
501
  raise ValueError(f'Failed to parse response: {raw_response!r}')
474
502
  else:
475
503
  response = {}
504
+
476
505
  if self._api_client.vertexai:
477
506
  response_dict = self._LiveServerMessage_from_vertex(response)
478
507
  else:
@@ -514,14 +543,26 @@ class AsyncSession:
514
543
  )
515
544
  if getv(from_object, ['turnComplete']) is not None:
516
545
  setv(to_object, ['turn_complete'], getv(from_object, ['turnComplete']))
517
- if getv(from_object, ['interrupted']) is not None:
518
- setv(to_object, ['interrupted'], getv(from_object, ['interrupted']))
519
546
  if getv(from_object, ['generationComplete']) is not None:
520
547
  setv(
521
548
  to_object,
522
549
  ['generation_complete'],
523
550
  getv(from_object, ['generationComplete']),
524
551
  )
552
+ if getv(from_object, ['inputTranscription']) is not None:
553
+ setv(
554
+ to_object,
555
+ ['input_transcription'],
556
+ getv(from_object, ['inputTranscription']),
557
+ )
558
+ if getv(from_object, ['outputTranscription']) is not None:
559
+ setv(
560
+ to_object,
561
+ ['output_transcription'],
562
+ getv(from_object, ['outputTranscription']),
563
+ )
564
+ if getv(from_object, ['interrupted']) is not None:
565
+ setv(to_object, ['interrupted'], getv(from_object, ['interrupted']))
525
566
  return to_object
526
567
 
527
568
  def _LiveToolCall_from_mldev(
@@ -550,6 +591,128 @@ class AsyncSession:
550
591
  )
551
592
  return to_object
552
593
 
594
+ def _LiveServerGoAway_from_mldev(
595
+ self,
596
+ from_object: Union[dict, object],
597
+ parent_object: Optional[dict] = None,
598
+ ) -> dict:
599
+ to_object: dict[str, Any] = {}
600
+ if getv(from_object, ['timeLeft']) is not None:
601
+ setv(to_object, ['time_left'], getv(from_object, ['timeLeft']))
602
+
603
+ return to_object
604
+
605
+ def _LiveServerSessionResumptionUpdate_from_mldev(
606
+ self,
607
+ from_object: Union[dict, object],
608
+ parent_object: Optional[dict] = None,
609
+ ) -> dict:
610
+ to_object: dict[str, Any] = {}
611
+ if getv(from_object, ['newHandle']) is not None:
612
+ setv(to_object, ['new_handle'], getv(from_object, ['newHandle']))
613
+
614
+ if getv(from_object, ['resumable']) is not None:
615
+ setv(to_object, ['resumable'], getv(from_object, ['resumable']))
616
+
617
+ if getv(from_object, ['lastConsumedClientMessageIndex']) is not None:
618
+ setv(
619
+ to_object,
620
+ ['last_consumed_client_message_index'],
621
+ getv(from_object, ['lastConsumedClientMessageIndex']),
622
+ )
623
+
624
+ return to_object
625
+
626
+ def _ModalityTokenCount_from_mldev(
627
+ self,
628
+ from_object: Union[dict, object],
629
+ ) -> Dict[str, Any]:
630
+ to_object: Dict[str, Any] = {}
631
+ if getv(from_object, ['modality']) is not None:
632
+ setv(to_object, ['modality'], getv(from_object, ['modality']))
633
+ if getv(from_object, ['tokenCount']) is not None:
634
+ setv(to_object, ['token_count'], getv(from_object, ['tokenCount']))
635
+ return to_object
636
+
637
+ def _UsageMetadata_from_mldev(
638
+ self,
639
+ from_object: Union[dict, object],
640
+ ) -> Dict[str, Any]:
641
+ to_object: dict[str, Any] = {}
642
+ if getv(from_object, ['promptTokenCount']) is not None:
643
+ setv(
644
+ to_object,
645
+ ['prompt_token_count'],
646
+ getv(from_object, ['promptTokenCount']),
647
+ )
648
+ if getv(from_object, ['cachedContentTokenCount']) is not None:
649
+ setv(
650
+ to_object,
651
+ ['cached_content_token_count'],
652
+ getv(from_object, ['cachedContentTokenCount']),
653
+ )
654
+ if getv(from_object, ['responseTokenCount']) is not None:
655
+ setv(
656
+ to_object,
657
+ ['response_token_count'],
658
+ getv(from_object, ['responseTokenCount']),
659
+ )
660
+ if getv(from_object, ['toolUsePromptTokenCount']) is not None:
661
+ setv(
662
+ to_object,
663
+ ['tool_use_prompt_token_count'],
664
+ getv(from_object, ['toolUsePromptTokenCount']),
665
+ )
666
+ if getv(from_object, ['thoughtsTokenCount']) is not None:
667
+ setv(
668
+ to_object,
669
+ ['thoughts_token_count'],
670
+ getv(from_object, ['thoughtsTokenCount']),
671
+ )
672
+ if getv(from_object, ['totalTokenCount']) is not None:
673
+ setv(
674
+ to_object,
675
+ ['total_token_count'],
676
+ getv(from_object, ['totalTokenCount']),
677
+ )
678
+ if getv(from_object, ['promptTokensDetails']) is not None:
679
+ setv(
680
+ to_object,
681
+ ['prompt_tokens_details'],
682
+ [
683
+ self._ModalityTokenCount_from_mldev(item)
684
+ for item in getv(from_object, ['promptTokensDetails'])
685
+ ],
686
+ )
687
+ if getv(from_object, ['cacheTokensDetails']) is not None:
688
+ setv(
689
+ to_object,
690
+ ['cache_tokens_details'],
691
+ [
692
+ self._ModalityTokenCount_from_mldev(item)
693
+ for item in getv(from_object, ['cacheTokensDetails'])
694
+ ],
695
+ )
696
+ if getv(from_object, ['responseTokensDetails']) is not None:
697
+ setv(
698
+ to_object,
699
+ ['response_tokens_details'],
700
+ [
701
+ self._ModalityTokenCount_from_mldev(item)
702
+ for item in getv(from_object, ['responseTokensDetails'])
703
+ ],
704
+ )
705
+ if getv(from_object, ['toolUsePromptTokensDetails']) is not None:
706
+ setv(
707
+ to_object,
708
+ ['tool_use_prompt_tokens_details'],
709
+ [
710
+ self._ModalityTokenCount_from_mldev(item)
711
+ for item in getv(from_object, ['toolUsePromptTokensDetails'])
712
+ ],
713
+ )
714
+ return to_object
715
+
553
716
  def _LiveServerMessage_from_mldev(
554
717
  self,
555
718
  from_object: Union[dict, object],
@@ -575,6 +738,34 @@ class AsyncSession:
575
738
  ['tool_call_cancellation'],
576
739
  getv(from_object, ['toolCallCancellation']),
577
740
  )
741
+
742
+ if getv(from_object, ['goAway']) is not None:
743
+ setv(
744
+ to_object,
745
+ ['go_away'],
746
+ self._LiveServerGoAway_from_mldev(
747
+ getv(from_object, ['goAway']), to_object
748
+ ),
749
+ )
750
+
751
+ if getv(from_object, ['sessionResumptionUpdate']) is not None:
752
+ setv(
753
+ to_object,
754
+ ['session_resumption_update'],
755
+ self._LiveServerSessionResumptionUpdate_from_mldev(
756
+ getv(from_object, ['sessionResumptionUpdate']),
757
+ to_object,
758
+ ),
759
+ )
760
+
761
+ return to_object
762
+
763
+ if getv(from_object, ['usageMetadata']) is not None:
764
+ setv(
765
+ to_object,
766
+ ['usage_metadata'],
767
+ self._UsageMetadata_from_mldev(getv(from_object, ['usageMetadata'])),
768
+ )
578
769
  return to_object
579
770
 
580
771
  def _LiveServerContent_from_vertex(
@@ -599,7 +790,6 @@ class AsyncSession:
599
790
  ['generation_complete'],
600
791
  getv(from_object, ['generationComplete']),
601
792
  )
602
- # Vertex supports transcription.
603
793
  if getv(from_object, ['inputTranscription']) is not None:
604
794
  setv(
605
795
  to_object,
@@ -616,6 +806,133 @@ class AsyncSession:
616
806
  setv(to_object, ['interrupted'], getv(from_object, ['interrupted']))
617
807
  return to_object
618
808
 
809
+ def _LiveServerGoAway_from_vertex(
810
+ self,
811
+ from_object: Union[dict, object],
812
+ ) -> dict:
813
+ to_object: dict[str, Any] = {}
814
+ if getv(from_object, ['timeLeft']) is not None:
815
+ setv(to_object, ['time_left'], getv(from_object, ['timeLeft']))
816
+
817
+ return to_object
818
+
819
+ def _LiveServerSessionResumptionUpdate_from_vertex(
820
+ self,
821
+ from_object: Union[dict, object],
822
+ ) -> dict:
823
+ to_object: dict[str, Any] = {}
824
+ if getv(from_object, ['newHandle']) is not None:
825
+ setv(to_object, ['new_handle'], getv(from_object, ['newHandle']))
826
+
827
+ if getv(from_object, ['resumable']) is not None:
828
+ setv(to_object, ['resumable'], getv(from_object, ['resumable']))
829
+
830
+ if getv(from_object, ['lastConsumedClientMessageIndex']) is not None:
831
+ setv(
832
+ to_object,
833
+ ['last_consumed_client_message_index'],
834
+ getv(from_object, ['lastConsumedClientMessageIndex']),
835
+ )
836
+
837
+ return to_object
838
+
839
+
840
+ def _ModalityTokenCount_from_vertex(
841
+ self,
842
+ from_object: Union[dict, object],
843
+ ) -> Dict[str, Any]:
844
+ to_object: Dict[str, Any] = {}
845
+ if getv(from_object, ['modality']) is not None:
846
+ setv(to_object, ['modality'], getv(from_object, ['modality']))
847
+ if getv(from_object, ['tokenCount']) is not None:
848
+ setv(to_object, ['token_count'], getv(from_object, ['tokenCount']))
849
+ return to_object
850
+
851
+ def _UsageMetadata_from_vertex(
852
+ self,
853
+ from_object: Union[dict, object],
854
+ ) -> Dict[str, Any]:
855
+ to_object: dict[str, Any] = {}
856
+ if getv(from_object, ['promptTokenCount']) is not None:
857
+ setv(
858
+ to_object,
859
+ ['prompt_token_count'],
860
+ getv(from_object, ['promptTokenCount']),
861
+ )
862
+ if getv(from_object, ['cachedContentTokenCount']) is not None:
863
+ setv(
864
+ to_object,
865
+ ['cached_content_token_count'],
866
+ getv(from_object, ['cachedContentTokenCount']),
867
+ )
868
+ if getv(from_object, ['candidatesTokenCount']) is not None:
869
+ setv(
870
+ to_object,
871
+ ['response_token_count'],
872
+ getv(from_object, ['candidatesTokenCount']),
873
+ )
874
+ if getv(from_object, ['toolUsePromptTokenCount']) is not None:
875
+ setv(
876
+ to_object,
877
+ ['tool_use_prompt_token_count'],
878
+ getv(from_object, ['toolUsePromptTokenCount']),
879
+ )
880
+ if getv(from_object, ['thoughtsTokenCount']) is not None:
881
+ setv(
882
+ to_object,
883
+ ['thoughts_token_count'],
884
+ getv(from_object, ['thoughtsTokenCount']),
885
+ )
886
+ if getv(from_object, ['totalTokenCount']) is not None:
887
+ setv(
888
+ to_object,
889
+ ['total_token_count'],
890
+ getv(from_object, ['totalTokenCount']),
891
+ )
892
+ if getv(from_object, ['promptTokensDetails']) is not None:
893
+ setv(
894
+ to_object,
895
+ ['prompt_tokens_details'],
896
+ [
897
+ self._ModalityTokenCount_from_vertex(item)
898
+ for item in getv(from_object, ['promptTokensDetails'])
899
+ ],
900
+ )
901
+ if getv(from_object, ['cacheTokensDetails']) is not None:
902
+ setv(
903
+ to_object,
904
+ ['cache_tokens_details'],
905
+ [
906
+ self._ModalityTokenCount_from_vertex(item)
907
+ for item in getv(from_object, ['cacheTokensDetails'])
908
+ ],
909
+ )
910
+ if getv(from_object, ['toolUsePromptTokensDetails']) is not None:
911
+ setv(
912
+ to_object,
913
+ ['tool_use_prompt_tokens_details'],
914
+ [
915
+ self._ModalityTokenCount_from_vertex(item)
916
+ for item in getv(from_object, ['toolUsePromptTokensDetails'])
917
+ ],
918
+ )
919
+ if getv(from_object, ['candidatesTokensDetails']) is not None:
920
+ setv(
921
+ to_object,
922
+ ['response_tokens_details'],
923
+ [
924
+ self._ModalityTokenCount_from_vertex(item)
925
+ for item in getv(from_object, ['candidatesTokensDetails'])
926
+ ],
927
+ )
928
+ if getv(from_object, ['trafficType']) is not None:
929
+ setv(
930
+ to_object,
931
+ ['traffic_type'],
932
+ getv(from_object, ['trafficType']),
933
+ )
934
+ return to_object
935
+
619
936
  def _LiveServerMessage_from_vertex(
620
937
  self,
621
938
  from_object: Union[dict, object],
@@ -629,7 +946,6 @@ class AsyncSession:
629
946
  getv(from_object, ['serverContent'])
630
947
  ),
631
948
  )
632
-
633
949
  if getv(from_object, ['toolCall']) is not None:
634
950
  setv(
635
951
  to_object,
@@ -642,6 +958,31 @@ class AsyncSession:
642
958
  ['tool_call_cancellation'],
643
959
  getv(from_object, ['toolCallCancellation']),
644
960
  )
961
+
962
+ if getv(from_object, ['goAway']) is not None:
963
+ setv(
964
+ to_object,
965
+ ['go_away'],
966
+ self._LiveServerGoAway_from_vertex(
967
+ getv(from_object, ['goAway'])
968
+ ),
969
+ )
970
+
971
+ if getv(from_object, ['sessionResumptionUpdate']) is not None:
972
+ setv(
973
+ to_object,
974
+ ['session_resumption_update'],
975
+ self._LiveServerSessionResumptionUpdate_from_vertex(
976
+ getv(from_object, ['sessionResumptionUpdate']),
977
+ ),
978
+ )
979
+
980
+ if getv(from_object, ['usageMetadata']) is not None:
981
+ setv(
982
+ to_object,
983
+ ['usage_metadata'],
984
+ self._UsageMetadata_from_vertex(getv(from_object, ['usageMetadata'])),
985
+ )
645
986
  return to_object
646
987
 
647
988
  def _parse_client_message(
@@ -1026,7 +1367,7 @@ def _t_tool_response(
1026
1367
 
1027
1368
 
1028
1369
  class AsyncLive(_api_module.BaseModule):
1029
- """AsyncLive. The live module is experimental."""
1370
+ """[Preview] AsyncLive."""
1030
1371
 
1031
1372
  def _LiveSetup_to_mldev(
1032
1373
  self, model: str, config: Optional[types.LiveConnectConfig] = None
@@ -1099,6 +1440,15 @@ class AsyncLive(_api_module.BaseModule):
1099
1440
  to_object['generationConfig'] = {
1100
1441
  'maxOutputTokens': getv(config, ['max_output_tokens'])
1101
1442
  }
1443
+ if getv(config, ['media_resolution']) is not None:
1444
+ if getv(to_object, ['generationConfig']) is not None:
1445
+ to_object['generationConfig']['mediaResolution'] = getv(
1446
+ config, ['media_resolution']
1447
+ )
1448
+ else:
1449
+ to_object['generationConfig'] = {
1450
+ 'mediaResolution': getv(config, ['media_resolution'])
1451
+ }
1102
1452
  if getv(config, ['seed']) is not None:
1103
1453
  if getv(to_object, ['generationConfig']) is not None:
1104
1454
  to_object['generationConfig']['seed'] = getv(config, ['seed'])
@@ -1127,11 +1477,84 @@ class AsyncLive(_api_module.BaseModule):
1127
1477
  for item in t.t_tools(self._api_client, getv(config, ['tools']))
1128
1478
  ],
1129
1479
  )
1480
+ if getv(config, ['input_audio_transcription']) is not None:
1481
+ raise ValueError('input_audio_transcription is not supported in MLDev '
1482
+ 'API.')
1483
+ if getv(config, ['output_audio_transcription']) is not None:
1484
+ setv(
1485
+ to_object,
1486
+ ['outputAudioTranscription'],
1487
+ _AudioTranscriptionConfig_to_mldev(
1488
+ self._api_client,
1489
+ getv(config, ['output_audio_transcription']),
1490
+ ),
1491
+ )
1492
+
1493
+ if getv(config, ['session_resumption']) is not None:
1494
+ setv(
1495
+ to_object,
1496
+ ['sessionResumption'],
1497
+ self._LiveClientSessionResumptionConfig_to_mldev(
1498
+ getv(config, ['session_resumption'])
1499
+ ),
1500
+ )
1501
+
1502
+ if getv(config, ['context_window_compression']) is not None:
1503
+ setv(
1504
+ to_object,
1505
+ ['contextWindowCompression'],
1506
+ self._ContextWindowCompressionConfig_to_mldev(
1507
+ getv(config, ['context_window_compression']),
1508
+ ),
1509
+ )
1130
1510
 
1131
1511
  return_value = {'setup': {'model': model}}
1132
1512
  return_value['setup'].update(to_object)
1133
1513
  return return_value
1134
1514
 
1515
+ def _SlidingWindow_to_mldev(
1516
+ self,
1517
+ from_object: Union[dict, object],
1518
+ ) -> dict:
1519
+ to_object: dict[str, Any] = {}
1520
+ if getv(from_object, ['target_tokens']) is not None:
1521
+ setv(to_object, ['targetTokens'], getv(from_object, ['target_tokens']))
1522
+
1523
+ return to_object
1524
+
1525
+
1526
+ def _ContextWindowCompressionConfig_to_mldev(
1527
+ self,
1528
+ from_object: Union[dict, object],
1529
+ ) -> dict:
1530
+ to_object: dict[str, Any] = {}
1531
+ if getv(from_object, ['trigger_tokens']) is not None:
1532
+ setv(to_object, ['triggerTokens'], getv(from_object, ['trigger_tokens']))
1533
+
1534
+ if getv(from_object, ['sliding_window']) is not None:
1535
+ setv(
1536
+ to_object,
1537
+ ['slidingWindow'],
1538
+ self._SlidingWindow_to_mldev(
1539
+ getv(from_object, ['sliding_window'])
1540
+ ),
1541
+ )
1542
+
1543
+ return to_object
1544
+
1545
+ def _LiveClientSessionResumptionConfig_to_mldev(
1546
+ self,
1547
+ from_object: Union[dict, object]
1548
+ ) -> dict:
1549
+ to_object: dict[str, Any] = {}
1550
+ if getv(from_object, ['handle']) is not None:
1551
+ setv(to_object, ['handle'], getv(from_object, ['handle']))
1552
+
1553
+ if getv(from_object, ['transparent']) is not None:
1554
+ raise ValueError('The `transparent` field is not supported in MLDev API')
1555
+
1556
+ return to_object
1557
+
1135
1558
  def _LiveSetup_to_vertex(
1136
1559
  self, model: str, config: Optional[types.LiveConnectConfig] = None
1137
1560
  ):
@@ -1212,6 +1635,15 @@ class AsyncLive(_api_module.BaseModule):
1212
1635
  to_object['generationConfig'] = {
1213
1636
  'maxOutputTokens': getv(config, ['max_output_tokens'])
1214
1637
  }
1638
+ if getv(config, ['media_resolution']) is not None:
1639
+ if getv(to_object, ['generationConfig']) is not None:
1640
+ to_object['generationConfig']['mediaResolution'] = getv(
1641
+ config, ['media_resolution']
1642
+ )
1643
+ else:
1644
+ to_object['generationConfig'] = {
1645
+ 'mediaResolution': getv(config, ['media_resolution'])
1646
+ }
1215
1647
  if getv(config, ['seed']) is not None:
1216
1648
  if getv(to_object, ['generationConfig']) is not None:
1217
1649
  to_object['generationConfig']['seed'] = getv(config, ['seed'])
@@ -1259,13 +1691,70 @@ class AsyncLive(_api_module.BaseModule):
1259
1691
  ),
1260
1692
  )
1261
1693
 
1694
+ if getv(config, ['session_resumption']) is not None:
1695
+ setv(
1696
+ to_object,
1697
+ ['sessionResumption'],
1698
+ self._LiveClientSessionResumptionConfig_to_vertex(
1699
+ getv(config, ['session_resumption'])
1700
+ ),
1701
+ )
1702
+
1703
+ if getv(config, ['context_window_compression']) is not None:
1704
+ setv(
1705
+ to_object,
1706
+ ['contextWindowCompression'],
1707
+ self._ContextWindowCompressionConfig_to_vertex(
1708
+ getv(config, ['context_window_compression']),
1709
+ ),
1710
+ )
1711
+
1262
1712
  return_value = {'setup': {'model': model}}
1263
1713
  return_value['setup'].update(to_object)
1264
1714
  return return_value
1265
1715
 
1266
- @experimental_warning(
1267
- 'The live API is experimental and may change in future versions.',
1268
- )
1716
+ def _SlidingWindow_to_vertex(
1717
+ self,
1718
+ from_object: Union[dict, object],
1719
+ ) -> dict:
1720
+ to_object: dict[str, Any] = {}
1721
+ if getv(from_object, ['target_tokens']) is not None:
1722
+ setv(to_object, ['targetTokens'], getv(from_object, ['target_tokens']))
1723
+
1724
+ return to_object
1725
+
1726
+ def _ContextWindowCompressionConfig_to_vertex(
1727
+ self,
1728
+ from_object: Union[dict, object],
1729
+ ) -> dict:
1730
+ to_object: dict[str, Any] = {}
1731
+ if getv(from_object, ['trigger_tokens']) is not None:
1732
+ setv(to_object, ['triggerTokens'], getv(from_object, ['trigger_tokens']))
1733
+
1734
+ if getv(from_object, ['sliding_window']) is not None:
1735
+ setv(
1736
+ to_object,
1737
+ ['slidingWindow'],
1738
+ self._SlidingWindow_to_mldev(
1739
+ getv(from_object, ['sliding_window'])
1740
+ ),
1741
+ )
1742
+
1743
+ return to_object
1744
+
1745
+ def _LiveClientSessionResumptionConfig_to_vertex(
1746
+ self,
1747
+ from_object: Union[dict, object]
1748
+ ) -> dict:
1749
+ to_object: dict[str, Any] = {}
1750
+ if getv(from_object, ['handle']) is not None:
1751
+ setv(to_object, ['handle'], getv(from_object, ['handle']))
1752
+
1753
+ if getv(from_object, ['transparent']) is not None:
1754
+ setv(to_object, ['transparent'], getv(from_object, ['transparent']))
1755
+
1756
+ return to_object
1757
+
1269
1758
  @contextlib.asynccontextmanager
1270
1759
  async def connect(
1271
1760
  self,
@@ -1273,9 +1762,9 @@ class AsyncLive(_api_module.BaseModule):
1273
1762
  model: str,
1274
1763
  config: Optional[types.LiveConnectConfigOrDict] = None,
1275
1764
  ) -> AsyncIterator[AsyncSession]:
1276
- """Connect to the live server.
1765
+ """[Preview] Connect to the live server.
1277
1766
 
1278
- The live module is experimental.
1767
+ Note: the live API is currently in preview.
1279
1768
 
1280
1769
  Usage:
1281
1770
 
@@ -1290,32 +1779,8 @@ class AsyncLive(_api_module.BaseModule):
1290
1779
  """
1291
1780
  base_url = self._api_client._websocket_base_url()
1292
1781
  transformed_model = t.t_model(self._api_client, model)
1293
- # Ensure the config is a LiveConnectConfig.
1294
- if config is None:
1295
- parameter_model = types.LiveConnectConfig()
1296
- elif isinstance(config, dict):
1297
- if config.get('system_instruction') is None:
1298
- system_instruction = None
1299
- else:
1300
- system_instruction = t.t_content(
1301
- self._api_client, config.get('system_instruction')
1302
- )
1303
- parameter_model = types.LiveConnectConfig(
1304
- generation_config=config.get('generation_config'),
1305
- response_modalities=config.get('response_modalities'),
1306
- speech_config=config.get('speech_config'),
1307
- temperature=config.get('temperature'),
1308
- top_p=config.get('top_p'),
1309
- top_k=config.get('top_k'),
1310
- max_output_tokens=config.get('max_output_tokens'),
1311
- seed=config.get('seed'),
1312
- system_instruction=system_instruction,
1313
- tools=config.get('tools'),
1314
- input_audio_transcription=config.get('input_audio_transcription'),
1315
- output_audio_transcription=config.get('output_audio_transcription'),
1316
- )
1317
- else:
1318
- parameter_model = config
1782
+
1783
+ parameter_model = _t_live_connect_config(self._api_client, config)
1319
1784
 
1320
1785
  if self._api_client.api_key:
1321
1786
  api_key = self._api_client.api_key
@@ -1374,3 +1839,37 @@ class AsyncLive(_api_module.BaseModule):
1374
1839
  logger.info(await ws.recv())
1375
1840
 
1376
1841
  yield AsyncSession(api_client=self._api_client, websocket=ws)
1842
+
1843
+
1844
+ def _t_live_connect_config(
1845
+ api_client: BaseApiClient,
1846
+ config: Optional[types.LiveConnectConfigOrDict],
1847
+ ) -> types.LiveConnectConfig:
1848
+ # Ensure the config is a LiveConnectConfig.
1849
+ if config is None:
1850
+ parameter_model = types.LiveConnectConfig()
1851
+ elif isinstance(config, dict):
1852
+ system_instruction = config.pop('system_instruction', None)
1853
+ if system_instruction is not None:
1854
+ converted_system_instruction = t.t_content(
1855
+ api_client, content=system_instruction
1856
+ )
1857
+ else:
1858
+ converted_system_instruction = None
1859
+ parameter_model = types.LiveConnectConfig(
1860
+ system_instruction=converted_system_instruction,
1861
+ **config
1862
+ ) # type: ignore
1863
+ else:
1864
+ parameter_model = config
1865
+
1866
+ if parameter_model.generation_config is not None:
1867
+ warnings.warn(
1868
+ 'Setting `LiveConnectConfig.generation_config` is deprecated, '
1869
+ 'please set the fields on `LiveConnectConfig` directly. This will '
1870
+ 'become an error in a future version (not before Q3 2025)',
1871
+ DeprecationWarning,
1872
+ stacklevel=4,
1873
+ )
1874
+
1875
+ return parameter_model