google-genai 1.16.1__py3-none-any.whl → 1.18.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/caches.py CHANGED
@@ -66,6 +66,24 @@ def _Blob_to_mldev(
66
66
  return to_object
67
67
 
68
68
 
69
+ def _FileData_to_mldev(
70
+ api_client: BaseApiClient,
71
+ from_object: Union[dict[str, Any], object],
72
+ parent_object: Optional[dict[str, Any]] = None,
73
+ ) -> dict[str, Any]:
74
+ to_object: dict[str, Any] = {}
75
+ if getv(from_object, ['display_name']) is not None:
76
+ raise ValueError('display_name parameter is not supported in Gemini API.')
77
+
78
+ if getv(from_object, ['file_uri']) is not None:
79
+ setv(to_object, ['fileUri'], getv(from_object, ['file_uri']))
80
+
81
+ if getv(from_object, ['mime_type']) is not None:
82
+ setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
83
+
84
+ return to_object
85
+
86
+
69
87
  def _Part_to_mldev(
70
88
  api_client: BaseApiClient,
71
89
  from_object: Union[dict[str, Any], object],
@@ -93,6 +111,22 @@ def _Part_to_mldev(
93
111
  ),
94
112
  )
95
113
 
114
+ if getv(from_object, ['file_data']) is not None:
115
+ setv(
116
+ to_object,
117
+ ['fileData'],
118
+ _FileData_to_mldev(
119
+ api_client, getv(from_object, ['file_data']), to_object
120
+ ),
121
+ )
122
+
123
+ if getv(from_object, ['thought_signature']) is not None:
124
+ setv(
125
+ to_object,
126
+ ['thoughtSignature'],
127
+ getv(from_object, ['thought_signature']),
128
+ )
129
+
96
130
  if getv(from_object, ['code_execution_result']) is not None:
97
131
  setv(
98
132
  to_object,
@@ -103,9 +137,6 @@ def _Part_to_mldev(
103
137
  if getv(from_object, ['executable_code']) is not None:
104
138
  setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
105
139
 
106
- if getv(from_object, ['file_data']) is not None:
107
- setv(to_object, ['fileData'], getv(from_object, ['file_data']))
108
-
109
140
  if getv(from_object, ['function_call']) is not None:
110
141
  setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
111
142
 
@@ -428,6 +459,9 @@ def _RetrievalConfig_to_mldev(
428
459
  _LatLng_to_mldev(api_client, getv(from_object, ['lat_lng']), to_object),
429
460
  )
430
461
 
462
+ if getv(from_object, ['language_code']) is not None:
463
+ setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
464
+
431
465
  return to_object
432
466
 
433
467
 
@@ -704,6 +738,24 @@ def _Blob_to_vertex(
704
738
  return to_object
705
739
 
706
740
 
741
+ def _FileData_to_vertex(
742
+ api_client: BaseApiClient,
743
+ from_object: Union[dict[str, Any], object],
744
+ parent_object: Optional[dict[str, Any]] = None,
745
+ ) -> dict[str, Any]:
746
+ to_object: dict[str, Any] = {}
747
+ if getv(from_object, ['display_name']) is not None:
748
+ setv(to_object, ['displayName'], getv(from_object, ['display_name']))
749
+
750
+ if getv(from_object, ['file_uri']) is not None:
751
+ setv(to_object, ['fileUri'], getv(from_object, ['file_uri']))
752
+
753
+ if getv(from_object, ['mime_type']) is not None:
754
+ setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
755
+
756
+ return to_object
757
+
758
+
707
759
  def _Part_to_vertex(
708
760
  api_client: BaseApiClient,
709
761
  from_object: Union[dict[str, Any], object],
@@ -731,6 +783,22 @@ def _Part_to_vertex(
731
783
  ),
732
784
  )
733
785
 
786
+ if getv(from_object, ['file_data']) is not None:
787
+ setv(
788
+ to_object,
789
+ ['fileData'],
790
+ _FileData_to_vertex(
791
+ api_client, getv(from_object, ['file_data']), to_object
792
+ ),
793
+ )
794
+
795
+ if getv(from_object, ['thought_signature']) is not None:
796
+ setv(
797
+ to_object,
798
+ ['thoughtSignature'],
799
+ getv(from_object, ['thought_signature']),
800
+ )
801
+
734
802
  if getv(from_object, ['code_execution_result']) is not None:
735
803
  setv(
736
804
  to_object,
@@ -741,9 +809,6 @@ def _Part_to_vertex(
741
809
  if getv(from_object, ['executable_code']) is not None:
742
810
  setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
743
811
 
744
- if getv(from_object, ['file_data']) is not None:
745
- setv(to_object, ['fileData'], getv(from_object, ['file_data']))
746
-
747
812
  if getv(from_object, ['function_call']) is not None:
748
813
  setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
749
814
 
@@ -1084,6 +1149,9 @@ def _RetrievalConfig_to_vertex(
1084
1149
  ),
1085
1150
  )
1086
1151
 
1152
+ if getv(from_object, ['language_code']) is not None:
1153
+ setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
1154
+
1087
1155
  return to_object
1088
1156
 
1089
1157
 
google/genai/chats.py CHANGED
@@ -160,7 +160,7 @@ class _BaseChat:
160
160
  # Because the AFC input contains the entire curated chat history in
161
161
  # addition to the new user input, we need to truncate the AFC history
162
162
  # to deduplicate the existing chat history.
163
- automatic_function_calling_history[len(self._curated_history):]
163
+ automatic_function_calling_history[len(self._curated_history) :]
164
164
  if automatic_function_calling_history
165
165
  else [user_input]
166
166
  )
@@ -328,7 +328,7 @@ class Chat(_BaseChat):
328
328
  yield chunk
329
329
  automatic_function_calling_history = (
330
330
  chunk.automatic_function_calling_history
331
- if chunk.automatic_function_calling_history
331
+ if chunk is not None and chunk.automatic_function_calling_history
332
332
  else []
333
333
  )
334
334
  self.record_history(
@@ -495,9 +495,12 @@ class AsyncChat(_BaseChat):
495
495
  self.record_history(
496
496
  user_input=input_content,
497
497
  model_output=output_contents,
498
- automatic_function_calling_history=chunk.automatic_function_calling_history if chunk.automatic_function_calling_history else [],
498
+ automatic_function_calling_history=chunk.automatic_function_calling_history
499
+ if chunk is not None and chunk.automatic_function_calling_history
500
+ else [],
499
501
  is_valid=is_valid,
500
502
  )
503
+
501
504
  return async_generator() # type: ignore[no-untyped-call, no-any-return]
502
505
 
503
506
 
google/genai/live.py CHANGED
@@ -34,6 +34,7 @@ from . import _live_converters as live_converters
34
34
  from . import _mcp_utils
35
35
  from . import _transformers as t
36
36
  from . import client
37
+ from . import errors
37
38
  from . import types
38
39
  from ._api_client import BaseApiClient
39
40
  from ._common import get_value_by_path as getv
@@ -78,10 +79,6 @@ _FUNCTION_RESPONSE_REQUIRES_ID = (
78
79
  ' response of a ToolCall.FunctionalCalls in Google AI.'
79
80
  )
80
81
 
81
-
82
- _DUMMY_KEY = 'dummy_key'
83
-
84
-
85
82
  class AsyncSession:
86
83
  """[Preview] AsyncSession."""
87
84
 
@@ -912,25 +909,10 @@ class AsyncLive(_api_module.BaseModule):
912
909
  Yields:
913
910
  An AsyncSession object.
914
911
  """
915
- async with self._connect(
916
- model=model,
917
- config=config,
918
- ) as session:
919
- yield session
920
-
921
- @contextlib.asynccontextmanager
922
- async def _connect(
923
- self,
924
- *,
925
- model: Optional[str] = None,
926
- config: Optional[types.LiveConnectConfigOrDict] = None,
927
- uri: Optional[str] = None,
928
- ) -> AsyncIterator[AsyncSession]:
929
-
930
912
  # TODO(b/404946570): Support per request http options.
931
913
  if isinstance(config, dict):
932
914
  config = types.LiveConnectConfig(**config)
933
- if config and config.http_options and uri is None:
915
+ if config and config.http_options:
934
916
  raise ValueError(
935
917
  'google.genai.client.aio.live.connect() does not support'
936
918
  ' http_options at request-level in LiveConnectConfig yet. Please use'
@@ -944,11 +926,23 @@ class AsyncLive(_api_module.BaseModule):
944
926
 
945
927
  parameter_model = await _t_live_connect_config(self._api_client, config)
946
928
 
947
- if self._api_client.api_key:
948
- api_key = self._api_client.api_key
929
+ if self._api_client.api_key and not self._api_client.vertexai:
949
930
  version = self._api_client._http_options.api_version
950
- if uri is None:
951
- uri = f'{base_url}/ws/google.ai.generativelanguage.{version}.GenerativeService.BidiGenerateContent?key={api_key}'
931
+ api_key = self._api_client.api_key
932
+ method = 'BidiGenerateContent'
933
+ key_name = 'key'
934
+ if api_key.startswith('auth_tokens/'):
935
+ warnings.warn(
936
+ message=(
937
+ "The SDK's ephemeral token support is experimental, and may"
938
+ ' change in future versions.'
939
+ ),
940
+ category=errors.ExperimentalWarning,
941
+ )
942
+ method = 'BidiGenerateContentConstrained'
943
+ key_name = 'access_token'
944
+
945
+ uri = f'{base_url}/ws/google.ai.generativelanguage.{version}.GenerativeService.{method}?{key_name}={api_key}'
952
946
  headers = self._api_client._http_options.headers
953
947
 
954
948
  request_dict = _common.convert_to_dict(
@@ -964,6 +958,27 @@ class AsyncLive(_api_module.BaseModule):
964
958
 
965
959
  setv(request_dict, ['setup', 'model'], transformed_model)
966
960
 
961
+ request = json.dumps(request_dict)
962
+ elif self._api_client.api_key and self._api_client.vertexai:
963
+ # Headers already contains api key for express mode.
964
+ api_key = self._api_client.api_key
965
+ version = self._api_client._http_options.api_version
966
+ uri = f'{base_url}/ws/google.cloud.aiplatform.{version}.LlmBidiService/BidiGenerateContent'
967
+ headers = self._api_client._http_options.headers
968
+
969
+ request_dict = _common.convert_to_dict(
970
+ live_converters._LiveConnectParameters_to_vertex(
971
+ api_client=self._api_client,
972
+ from_object=types.LiveConnectParameters(
973
+ model=transformed_model,
974
+ config=parameter_model,
975
+ ).model_dump(exclude_none=True),
976
+ )
977
+ )
978
+ del request_dict['config']
979
+
980
+ setv(request_dict, ['setup', 'model'], transformed_model)
981
+
967
982
  request = json.dumps(request_dict)
968
983
  else:
969
984
  if not self._api_client._credentials:
@@ -1038,83 +1053,6 @@ class AsyncLive(_api_module.BaseModule):
1038
1053
  yield AsyncSession(api_client=self._api_client, websocket=ws)
1039
1054
 
1040
1055
 
1041
- @_common.experimental_warning(
1042
- "The SDK's Live API connection with ephemeral token implementation is"
1043
- ' experimental, and may change in future versions.',
1044
- )
1045
- @contextlib.asynccontextmanager
1046
- async def live_ephemeral_connect(
1047
- access_token: str,
1048
- model: Optional[str] = None,
1049
- config: Optional[types.LiveConnectConfigOrDict] = None,
1050
- ) -> AsyncIterator[AsyncSession]:
1051
- """[Experimental] Connect to the live server using ephermeral token (Gemini Developer API only).
1052
-
1053
- Note: the live API is currently in experimental.
1054
-
1055
- Usage:
1056
-
1057
- .. code-block:: python
1058
- from google import genai
1059
-
1060
- config = {}
1061
- async with genai.live_ephemeral_connect(
1062
- access_token='auth_tokens/12345',
1063
- model='...',
1064
- config=config,
1065
- http_options=types.HttpOptions(api_version='v1beta'),
1066
- ) as session:
1067
- await session.send_client_content(
1068
- turns=types.Content(
1069
- role='user',
1070
- parts=[types.Part(text='hello!')]
1071
- ),
1072
- turn_complete=True
1073
- )
1074
-
1075
- async for message in session.receive():
1076
- print(message)
1077
-
1078
- Args:
1079
- access_token: The access token to use for the Live session. It can be
1080
- generated by the `client.tokens.create` method.
1081
- model: The model to use for the Live session.
1082
- config: The configuration for the Live session.
1083
-
1084
- Yields:
1085
- An AsyncSession object.
1086
- """
1087
- if isinstance(config, dict):
1088
- config = types.LiveConnectConfig(**config)
1089
-
1090
- http_options = config.http_options if config else None
1091
-
1092
- base_url = (
1093
- http_options.base_url
1094
- if http_options and http_options.base_url
1095
- else 'https://generativelanguage.googleapis.com/'
1096
- )
1097
- api_version = (
1098
- http_options.api_version
1099
- if http_options and http_options.api_version
1100
- else 'v1beta'
1101
- )
1102
- internal_client = client.Client(
1103
- api_key=_DUMMY_KEY, # Can't be None during initialization
1104
- http_options=types.HttpOptions(
1105
- base_url=base_url,
1106
- api_version=api_version,
1107
- ),
1108
- )
1109
- websocket_base_url = internal_client._api_client._websocket_base_url()
1110
- uri = f'{websocket_base_url}/ws/google.ai.generativelanguage.{api_version}.GenerativeService.BidiGenerateContentConstrained?access_token={access_token}'
1111
-
1112
- async with internal_client.aio.live._connect(
1113
- model=model, config=config, uri=uri
1114
- ) as session:
1115
- yield session
1116
-
1117
-
1118
1056
  async def _t_live_connect_config(
1119
1057
  api_client: BaseApiClient,
1120
1058
  config: Optional[types.LiveConnectConfigOrDict],