google-genai 1.7.0__py3-none-any.whl → 1.53.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.
Files changed (42) hide show
  1. google/genai/__init__.py +4 -2
  2. google/genai/_adapters.py +55 -0
  3. google/genai/_api_client.py +1301 -299
  4. google/genai/_api_module.py +1 -1
  5. google/genai/_automatic_function_calling_util.py +54 -33
  6. google/genai/_base_transformers.py +26 -0
  7. google/genai/_base_url.py +50 -0
  8. google/genai/_common.py +560 -59
  9. google/genai/_extra_utils.py +371 -38
  10. google/genai/_live_converters.py +1467 -0
  11. google/genai/_local_tokenizer_loader.py +214 -0
  12. google/genai/_mcp_utils.py +117 -0
  13. google/genai/_operations_converters.py +394 -0
  14. google/genai/_replay_api_client.py +204 -92
  15. google/genai/_test_api_client.py +1 -1
  16. google/genai/_tokens_converters.py +520 -0
  17. google/genai/_transformers.py +633 -233
  18. google/genai/batches.py +1733 -538
  19. google/genai/caches.py +678 -1012
  20. google/genai/chats.py +48 -38
  21. google/genai/client.py +142 -15
  22. google/genai/documents.py +532 -0
  23. google/genai/errors.py +141 -35
  24. google/genai/file_search_stores.py +1296 -0
  25. google/genai/files.py +312 -744
  26. google/genai/live.py +617 -367
  27. google/genai/live_music.py +197 -0
  28. google/genai/local_tokenizer.py +395 -0
  29. google/genai/models.py +3598 -3116
  30. google/genai/operations.py +201 -362
  31. google/genai/pagers.py +23 -7
  32. google/genai/py.typed +1 -0
  33. google/genai/tokens.py +362 -0
  34. google/genai/tunings.py +1274 -496
  35. google/genai/types.py +14535 -5454
  36. google/genai/version.py +2 -2
  37. {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info}/METADATA +736 -234
  38. google_genai-1.53.0.dist-info/RECORD +41 -0
  39. {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info}/WHEEL +1 -1
  40. google_genai-1.7.0.dist-info/RECORD +0 -27
  41. {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info/licenses}/LICENSE +0 -0
  42. {google_genai-1.7.0.dist-info → google_genai-1.53.0.dist-info}/top_level.txt +0 -0
google/genai/pagers.py CHANGED
@@ -1,4 +1,4 @@
1
- # Copyright 2024 Google LLC
1
+ # Copyright 2025 Google LLC
2
2
  #
3
3
  # Licensed under the Apache License, Version 2.0 (the "License");
4
4
  # you may not use this file except in compliance with the License.
@@ -18,12 +18,20 @@
18
18
  # pylint: disable=protected-access
19
19
 
20
20
  import copy
21
- from typing import Any, AsyncIterator,Awaitable, Callable, Generic, Iterator, Literal, TypeVar
21
+ from typing import Any, AsyncIterator, Awaitable, Callable, Generic, Iterator, Literal, TypeVar, Union
22
+ from . import _common
23
+ from . import types
22
24
 
23
25
  T = TypeVar('T')
24
26
 
25
27
  PagedItem = Literal[
26
- 'batch_jobs', 'models', 'tuning_jobs', 'files', 'cached_contents'
28
+ 'batch_jobs',
29
+ 'models',
30
+ 'tuning_jobs',
31
+ 'files',
32
+ 'cached_contents',
33
+ 'file_search_stores',
34
+ 'documents',
27
35
  ]
28
36
 
29
37
 
@@ -36,13 +44,15 @@ class _BasePager(Generic[T]):
36
44
  request: Callable[..., Any],
37
45
  response: Any,
38
46
  config: Any,
39
- ):
47
+ ) -> None:
40
48
  self._name = name
41
49
  self._request = request
42
50
 
43
51
  self._page = getattr(response, self._name) or []
44
52
  self._idx = 0
45
53
 
54
+ self._sdk_http_response = getattr(response, 'sdk_http_response', None)
55
+
46
56
  if not config:
47
57
  request_config = {}
48
58
  elif isinstance(config, dict):
@@ -52,7 +62,7 @@ class _BasePager(Generic[T]):
52
62
  request_config['page_token'] = getattr(response, 'next_page_token')
53
63
  self._config = request_config
54
64
 
55
- self._page_size = request_config.get('page_size', len(self._page))
65
+ self._page_size: int = request_config.get('page_size', len(self._page))
56
66
 
57
67
  def __init__(
58
68
  self,
@@ -65,7 +75,7 @@ class _BasePager(Generic[T]):
65
75
 
66
76
  @property
67
77
  def page(self) -> list[T]:
68
- """Returns a subset of the entire list of items.
78
+ """Returns a subset of the entire list of items.
69
79
 
70
80
  For the number of items returned, see `pageSize()`.
71
81
 
@@ -111,7 +121,13 @@ class _BasePager(Generic[T]):
111
121
  return self._page_size
112
122
 
113
123
  @property
114
- def config(self) -> dict[str, Any]:
124
+ def sdk_http_response(self) -> Union[types.HttpResponse, None]:
125
+ """Returns the http response of the API response."""
126
+
127
+ return self._sdk_http_response
128
+
129
+ @property
130
+ def config(self) -> _common.StringDict:
115
131
  """Returns the configuration when making the API request for the next page.
116
132
 
117
133
  A configuration is a set of optional parameters and arguments that can be
google/genai/py.typed ADDED
@@ -0,0 +1 @@
1
+ # see: https://peps.python.org/pep-0561/
google/genai/tokens.py ADDED
@@ -0,0 +1,362 @@
1
+ # Copyright 2025 Google LLC
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+
16
+ """[Experimental] Auth Tokens API client."""
17
+
18
+ import json
19
+ import logging
20
+ from typing import Any, Dict, List, Optional
21
+ from urllib.parse import urlencode
22
+ from . import _api_module
23
+ from . import _common
24
+ from . import _tokens_converters as tokens_converters
25
+ from . import types
26
+
27
+ logger = logging.getLogger('google_genai.tokens')
28
+
29
+
30
+ def _get_field_masks(setup: _common.StringDict) -> str:
31
+ """Return field_masks"""
32
+ fields = []
33
+ for k, v in setup.items():
34
+ # 2nd layer, recursively get field masks see TODO(b/418290100)
35
+ if isinstance(v, dict) and v:
36
+ field = [f'{k}.{kk}' for kk in v.keys()]
37
+ else:
38
+ field = [k] # 1st layer
39
+ fields.extend(field)
40
+
41
+ return ','.join(fields)
42
+
43
+
44
+ def _convert_bidi_setup_to_token_setup(
45
+ request_dict: _common.StringDict,
46
+ config: Optional[types.CreateAuthTokenConfigOrDict] = None,
47
+ ) -> _common.StringDict:
48
+ """Converts bidiGenerateContentSetup."""
49
+ bidi_setup = request_dict.get('bidiGenerateContentSetup')
50
+ if bidi_setup and bidi_setup.get('setup'):
51
+ # Handling mismatch between AuthToken service and
52
+ # BidiGenerateContent service
53
+ request_dict['bidiGenerateContentSetup'] = bidi_setup.get('setup')
54
+
55
+ # Convert non null bidiGenerateContentSetup to field_mask
56
+ field_mask = _get_field_masks(request_dict['bidiGenerateContentSetup'])
57
+
58
+ if (
59
+ isinstance(config, dict)
60
+ and config.get('lock_additional_fields') is not None
61
+ and not config.get('lock_additional_fields')
62
+ ) or (
63
+ isinstance(config, types.CreateAuthTokenConfig)
64
+ and config.lock_additional_fields is not None
65
+ and not config.lock_additional_fields # pylint: disable=literal-comparison
66
+ ):
67
+ # Empty list, lock non null fields
68
+ request_dict['fieldMask'] = field_mask
69
+ elif (
70
+ isinstance(config, dict)
71
+ and config.get('lock_additional_fields') is None
72
+ ) or (
73
+ isinstance(config, types.CreateAuthTokenConfig)
74
+ and config.lock_additional_fields is None
75
+ ):
76
+ # None. Global lock. unset fieldMask
77
+ request_dict.pop('fieldMask', None)
78
+ elif request_dict['fieldMask']:
79
+ # Lock non null + additional fields
80
+ additional_fields_list: Optional[List[str]] = request_dict.get(
81
+ 'fieldMask'
82
+ )
83
+ generation_config_list = types.GenerationConfig().model_dump().keys()
84
+ if additional_fields_list:
85
+ field_mask_list = []
86
+ for field in additional_fields_list:
87
+ if field in generation_config_list:
88
+ field = f'generationConfig.{field}'
89
+ field_mask_list.append(field)
90
+ else:
91
+ field_mask_list = []
92
+ request_dict['fieldMask'] = (
93
+ field_mask + ',' + ','.join(field_mask_list)
94
+ if field_mask_list
95
+ else field_mask
96
+ )
97
+ else:
98
+ # Lock all fields
99
+ request_dict.pop('fieldMask', None)
100
+ else:
101
+ field_mask = request_dict.get('fieldMask', [])
102
+ field_mask_str = ','.join(field_mask)
103
+ if field_mask:
104
+ request_dict['fieldMask'] = field_mask_str
105
+ else:
106
+ request_dict.pop('fieldMask', None)
107
+ if not request_dict.get('bidiGenerateContentSetup'):
108
+ request_dict.pop('bidiGenerateContentSetup', None)
109
+
110
+ return request_dict
111
+
112
+
113
+ class Tokens(_api_module.BaseModule):
114
+ """[Experimental] Auth Tokens API client.
115
+
116
+ This class provides methods for creating auth tokens.
117
+ """
118
+
119
+ @_common.experimental_warning(
120
+ "The SDK's token creation implementation is experimental, "
121
+ 'and may change in future versions.',
122
+ )
123
+ def create(
124
+ self, *, config: Optional[types.CreateAuthTokenConfigOrDict] = None
125
+ ) -> types.AuthToken:
126
+ """[Experimental] Creates an auth token.
127
+
128
+ Args:
129
+ config (CreateAuthTokenConfig): Optional configuration for the request.
130
+
131
+ The CreateAuthTokenConfig's `live_constrained_parameters` attrubite
132
+ Can be used to lock the parameters of the live session so they
133
+ can't be changed client side. This behavior has two basic modes depending on
134
+ whether `lock_additional_fields` is set:
135
+
136
+ If you do not pass `lock_additional_fields` the entire
137
+ `live_constrained_parameters` is locked and can't be changed
138
+ by the token's user.
139
+
140
+ If you set `lock_additional_fields`, then the non-null fields of
141
+ `live_constrained_parameters` are locked, and any additional fields
142
+ specified in `lock_additional_fields`.
143
+
144
+ Usage:
145
+
146
+ .. code-block:: python
147
+
148
+ # Case 1: If LiveEphemeralParameters is unset, unlock LiveConnectConfig
149
+ # when using the token in Live API sessions. Each session connection can
150
+ # use a different configuration.
151
+
152
+ config = types.CreateAuthTokenConfig(
153
+ uses=10,
154
+ expire_time='2025-05-01T00:00:00Z',
155
+ )
156
+ auth_token = client.tokens.create(config=config)
157
+
158
+ .. code-block:: python
159
+
160
+ # Case 2: If LiveEphemeralParameters is set, lock all fields in
161
+ # LiveConnectConfig when using the token in Live API sessions. For
162
+ # example, changing `output_audio_transcription` in the Live API
163
+ # connection will be ignored by the API.
164
+
165
+ auth_token = client.tokens.create(
166
+ config=types.CreateAuthTokenConfig(
167
+ uses=10,
168
+ live_constrained_parameters=types.LiveEphemeralParameters(
169
+ model='gemini-live-2.5-flash-preview',
170
+ config=types.LiveConnectConfig(
171
+ system_instruction='You are an LLM called Gemini.'
172
+ ),
173
+ ),
174
+ )
175
+ )
176
+
177
+ .. code-block:: python
178
+
179
+ # Case 3: If LiveEphemeralParameters is set and lockAdditionalFields is
180
+ # empty, lock LiveConnectConfig with set fields (e.g.
181
+ # system_instruction in this example) when using the token in Live API
182
+ # sessions.
183
+ auth_token = client.tokens.create(
184
+ config=types.CreateAuthTokenConfig(
185
+ uses=10,
186
+ live_constrained_parameters=types.LiveEphemeralParameters(
187
+ config=types.LiveConnectConfig(
188
+ system_instruction='You are an LLM called Gemini.'
189
+ ),
190
+ ),
191
+ lock_additional_fields=[],
192
+ )
193
+ )
194
+
195
+ .. code-block:: python
196
+
197
+ # Case 4: If LiveEphemeralParameters is set and lockAdditionalFields is
198
+ # set, lock LiveConnectConfig with set and additional fields (e.g.
199
+ # system_instruction, temperature in this example) when using the token
200
+ # in Live API sessions.
201
+ auth_token = client.tokens.create(
202
+ config=types.CreateAuthTokenConfig(
203
+ uses=10,
204
+ live_constrained_parameters=types.LiveEphemeralParameters(
205
+ model='gemini-live-2.5-flash-preview',
206
+ config=types.LiveConnectConfig(
207
+ system_instruction='You are an LLM called Gemini.'
208
+ ),
209
+ ),
210
+ lock_additional_fields=['temperature'],
211
+ )
212
+ )
213
+ """
214
+
215
+ parameter_model = types.CreateAuthTokenParameters(
216
+ config=config,
217
+ )
218
+ request_url_dict: Optional[dict[str, str]]
219
+ if self._api_client.vertexai:
220
+ raise ValueError(
221
+ 'This method is only supported in the Gemini Developer client.'
222
+ )
223
+ else:
224
+ request_dict = tokens_converters._CreateAuthTokenParameters_to_mldev(
225
+ self._api_client,
226
+ parameter_model
227
+ )
228
+ request_url_dict = request_dict.get('_url')
229
+ if request_url_dict:
230
+ path = 'auth_tokens'.format_map(request_url_dict)
231
+ else:
232
+ path = 'auth_tokens'
233
+
234
+ query_params = request_dict.get('_query')
235
+ if query_params:
236
+ path = f'{path}?{urlencode(query_params)}'
237
+ # TODO: remove the hack that pops config.
238
+
239
+ request_dict.pop('config', None)
240
+
241
+ # Token creation request data need to replace 'setup' with
242
+ # 'bidiGenerateContentSetup'
243
+ if request_dict:
244
+ request_dict = _convert_bidi_setup_to_token_setup(request_dict, config)
245
+
246
+ http_options: Optional[types.HttpOptions] = None
247
+ if (
248
+ parameter_model is not None
249
+ and parameter_model.config is not None
250
+ and parameter_model.config.http_options is not None
251
+ ):
252
+ http_options = parameter_model.config.http_options
253
+
254
+ request_dict = _common.convert_to_dict(request_dict)
255
+ request_dict = _common.encode_unserializable_types(request_dict)
256
+
257
+ response = self._api_client.request(
258
+ 'post', path, request_dict, http_options
259
+ )
260
+ response_dict = {} if not response.body else json.loads(response.body)
261
+
262
+ return_value = types.AuthToken._from_response(
263
+ response=response_dict, kwargs=parameter_model.model_dump()
264
+ )
265
+ self._api_client._verify_response(return_value)
266
+ return return_value
267
+
268
+
269
+ class AsyncTokens(_api_module.BaseModule):
270
+ """[Experimental] Async Auth Tokens API client.
271
+
272
+ This class provides asynchronous methods for creating auth tokens.
273
+ """
274
+
275
+ @_common.experimental_warning(
276
+ "The SDK's token creation implementation is experimental, "
277
+ 'and may change in future versions.',
278
+ )
279
+ async def create(
280
+ self, *, config: Optional[types.CreateAuthTokenConfigOrDict] = None
281
+ ) -> types.AuthToken:
282
+ """Creates an auth token asynchronously. Support in v1alpha only.
283
+
284
+ Args:
285
+ config (CreateAuthTokenConfig): Optional configuration for the request.
286
+
287
+ Usage:
288
+
289
+ .. code-block:: python
290
+
291
+ client = genai.Client(
292
+ api_key=API_KEY,
293
+ http_options=types.HttpOptions(api_version='v1alpha'),
294
+ )
295
+
296
+ auth_token = await client.aio.tokens.create(
297
+ config=types.CreateAuthTokenConfig(
298
+ uses=10,
299
+ live_constrained_parameters=types.LiveEphemeralParameters(
300
+ model='gemini-live-2.5-flash-preview',
301
+ config=types.LiveConnectConfig(
302
+ system_instruction='You are an LLM called Gemini.'
303
+ ),
304
+ ),
305
+ )
306
+ )
307
+ """
308
+
309
+ parameter_model = types.CreateAuthTokenParameters(
310
+ config=config,
311
+ )
312
+
313
+ request_url_dict: Optional[dict[str, str]]
314
+ if self._api_client.vertexai:
315
+ raise ValueError(
316
+ 'This method is only supported in the Gemini Developer client.'
317
+ )
318
+ else:
319
+ request_dict = tokens_converters._CreateAuthTokenParameters_to_mldev(
320
+ self._api_client,
321
+ parameter_model
322
+ )
323
+ request_url_dict = request_dict.get('_url')
324
+ if request_url_dict:
325
+ path = 'auth_tokens'.format_map(request_url_dict)
326
+ else:
327
+ path = 'auth_tokens'
328
+
329
+ query_params = request_dict.get('_query')
330
+ if query_params:
331
+ path = f'{path}?{urlencode(query_params)}'
332
+ # TODO: remove the hack that pops config.
333
+ request_dict.pop('config', None)
334
+
335
+ # Token creation request data need to replace 'setup' with
336
+ # 'bidiGenerateContentSetup'
337
+ request_dict = _convert_bidi_setup_to_token_setup(request_dict, config)
338
+
339
+ http_options: Optional[types.HttpOptions] = None
340
+ if (
341
+ parameter_model is not None
342
+ and parameter_model.config is not None
343
+ and parameter_model.config.http_options is not None
344
+ ):
345
+ http_options = parameter_model.config.http_options
346
+
347
+ request_dict = _common.convert_to_dict(request_dict)
348
+ request_dict = _common.encode_unserializable_types(request_dict)
349
+
350
+ response = await self._api_client.async_request(
351
+ 'post',
352
+ path,
353
+ request_dict,
354
+ http_options=http_options,
355
+ )
356
+ response_dict = {} if not response.body else json.loads(response.body)
357
+
358
+ return_value = types.AuthToken._from_response(
359
+ response=response_dict, kwargs=parameter_model.model_dump()
360
+ )
361
+ self._api_client._verify_response(return_value)
362
+ return return_value