google-genai 1.15.0__py3-none-any.whl → 1.16.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/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.
google/genai/tokens.py ADDED
@@ -0,0 +1,357 @@
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 logging
19
+ from typing import Any, Dict, List, Optional
20
+ from urllib.parse import urlencode
21
+ from . import _api_module
22
+ from . import _common
23
+ from . import _tokens_converters as tokens_converters
24
+ from . import types
25
+
26
+ logger = logging.getLogger('google_genai.tokens')
27
+
28
+
29
+ def _get_field_masks(setup: Dict[str, Any]) -> str:
30
+ """Return field_masks"""
31
+ fields = []
32
+ for k, v in setup.items():
33
+ # 2nd layer, recursively get field masks see TODO(b/418290100)
34
+ if isinstance(v, dict) and v:
35
+ field = [f'{k}.{kk}' for kk in v.keys()]
36
+ else:
37
+ field = [k] # 1st layer
38
+ fields.extend(field)
39
+
40
+ return ','.join(fields)
41
+
42
+
43
+ def _convert_bidi_setup_to_token_setup(
44
+ request_dict: dict[str, Any],
45
+ config: Optional[types.CreateAuthTokenConfigOrDict] = None,
46
+ ) -> Dict[str, Any]:
47
+ """Converts bidiGenerateContentSetup."""
48
+ bidi_setup = request_dict.get('bidiGenerateContentSetup')
49
+ if bidi_setup and bidi_setup.get('setup'):
50
+ # Handling mismatch between AuthToken service and
51
+ # BidiGenerateContent service
52
+ request_dict['bidiGenerateContentSetup'] = bidi_setup.get('setup')
53
+
54
+ # Convert non null bidiGenerateContentSetup to field_mask
55
+ field_mask = _get_field_masks(request_dict['bidiGenerateContentSetup'])
56
+
57
+ if (
58
+ isinstance(config, dict)
59
+ and config.get('lock_additional_fields') is not None
60
+ and not config.get('lock_additional_fields')
61
+ ) or (
62
+ isinstance(config, types.CreateAuthTokenConfig)
63
+ and config.lock_additional_fields is not None
64
+ and not config.lock_additional_fields # pylint: disable=literal-comparison
65
+ ):
66
+ # Empty list, lock non null fields
67
+ request_dict['fieldMask'] = field_mask
68
+ elif (
69
+ isinstance(config, dict)
70
+ and config.get('lock_additional_fields') is None
71
+ ) or (
72
+ isinstance(config, types.CreateAuthTokenConfig)
73
+ and config.lock_additional_fields is None
74
+ ):
75
+ # None. Global lock. unset fieldMask
76
+ request_dict.pop('fieldMask', None)
77
+ elif request_dict['fieldMask']:
78
+ # Lock non null + additional fields
79
+ additional_fields_list: Optional[List[str]] = request_dict.get(
80
+ 'fieldMask'
81
+ )
82
+ generation_config_list = types.GenerationConfig().model_dump().keys()
83
+ if additional_fields_list:
84
+ field_mask_list = []
85
+ for field in additional_fields_list:
86
+ if field in generation_config_list:
87
+ field = f'generationConfig.{field}'
88
+ field_mask_list.append(field)
89
+ else:
90
+ field_mask_list = []
91
+ request_dict['fieldMask'] = (
92
+ field_mask + ',' + ','.join(field_mask_list)
93
+ if field_mask_list
94
+ else field_mask
95
+ )
96
+ else:
97
+ # Lock all fields
98
+ request_dict.pop('fieldMask', None)
99
+ else:
100
+ field_mask = request_dict.get('fieldMask', [])
101
+ field_mask_str = ','.join(field_mask)
102
+ if field_mask:
103
+ request_dict['fieldMask'] = field_mask_str
104
+ else:
105
+ request_dict.pop('fieldMask', None)
106
+ if not request_dict.get('bidiGenerateContentSetup'):
107
+ request_dict.pop('bidiGenerateContentSetup', None)
108
+
109
+ return request_dict
110
+
111
+
112
+ class Tokens(_api_module.BaseModule):
113
+ """[Experimental] Auth Tokens API client.
114
+
115
+ This class provides methods for creating auth tokens.
116
+ """
117
+
118
+ @_common.experimental_warning(
119
+ "The SDK's token creation implementation is experimental, "
120
+ 'and may change in future versions.',
121
+ )
122
+ def create(
123
+ self, *, config: Optional[types.CreateAuthTokenConfigOrDict] = None
124
+ ) -> types.AuthToken:
125
+ """[Experimental] Creates an auth token.
126
+
127
+ Args:
128
+ config (CreateAuthTokenConfig): Optional configuration for the request.
129
+
130
+ The CreateAuthTokenConfig's `live_constrained_parameters` attrubite
131
+ Can be used to lock the parameters of the live session so they
132
+ can't be changed client side. This behavior has two basic modes depending on
133
+ whether `lock_additional_fields` is set:
134
+
135
+ If you do not pass `lock_additional_fields` the entire
136
+ `live_constrained_parameters` is locked and can't be changed
137
+ by the token's user.
138
+
139
+ If you set `lock_additional_fields`, then the non-null fields of
140
+ `live_constrained_parameters` are locked, and any additional fields
141
+ specified in `lock_additional_fields`.
142
+
143
+ Usage:
144
+
145
+ .. code-block:: python
146
+ # Case 1: If LiveEphemeralParameters is unset, unlock LiveConnectConfig
147
+ # when using the token in Live API sessions. Each session connection can
148
+ # use a different configuration.
149
+
150
+ config = types.CreateAuthTokenConfig(
151
+ uses=10,
152
+ expire_time='2025-05-01T00:00:00Z',
153
+ )
154
+ auth_token = client.tokens.create(config=config)
155
+
156
+ .. code-block:: python
157
+ # Case 2: If LiveEphemeralParameters is set, lock all fields in
158
+ # LiveConnectConfig when using the token in Live API sessions. For
159
+ # example, changing `output_audio_transcription` in the Live API
160
+ # connection will be ignored by the API.
161
+
162
+ auth_token = client.tokens.create(
163
+ config=types.CreateAuthTokenConfig(
164
+ uses=10,
165
+ live_constrained_parameters=types.LiveEphemeralParameters(
166
+ model='gemini-2.0-flash-live-001',
167
+ config=types.LiveConnectConfig(
168
+ system_instruction='You are an LLM called Gemini.'
169
+ ),
170
+ ),
171
+ )
172
+ )
173
+ .. code-block:: python
174
+ # Case 3: If LiveEphemeralParameters is set and lockAdditionalFields is
175
+ # empty, lock LiveConnectConfig with set fields (e.g.
176
+ # system_instruction in this example) when using the token in Live API
177
+ # sessions.
178
+ auth_token = client.tokens.create(
179
+ config=types.CreateAuthTokenConfig(
180
+ uses=10,
181
+ live_constrained_parameters=types.LiveEphemeralParameters(
182
+ config=types.LiveConnectConfig(
183
+ system_instruction='You are an LLM called Gemini.'
184
+ ),
185
+ ),
186
+ lock_additional_fields=[],
187
+ )
188
+ )
189
+
190
+ .. code-block:: python
191
+ # Case 4: If LiveEphemeralParameters is set and lockAdditionalFields is
192
+ # set, lock LiveConnectConfig with set and additional fields (e.g.
193
+ # system_instruction, temperature in this example) when using the token
194
+ # in Live API sessions.
195
+ auth_token = client.tokens.create(
196
+ config=types.CreateAuthTokenConfig(
197
+ uses=10,
198
+ live_constrained_parameters=types.LiveEphemeralParameters(
199
+ model='gemini-2.0-flash-live-001',
200
+ config=types.LiveConnectConfig(
201
+ system_instruction='You are an LLM called Gemini.'
202
+ ),
203
+ ),
204
+ lock_additional_fields=['temperature'],
205
+ )
206
+ )
207
+ """
208
+
209
+ parameter_model = types.CreateAuthTokenParameters(
210
+ config=config,
211
+ )
212
+ request_url_dict: Optional[dict[str, str]]
213
+ if self._api_client.vertexai:
214
+ raise ValueError(
215
+ 'This method is only supported in the Gemini Developer client.'
216
+ )
217
+ else:
218
+ request_dict = tokens_converters._CreateAuthTokenParameters_to_mldev(
219
+ self._api_client, parameter_model
220
+ )
221
+ request_url_dict = request_dict.get('_url')
222
+ if request_url_dict:
223
+ path = 'auth_tokens'.format_map(request_url_dict)
224
+ else:
225
+ path = 'auth_tokens'
226
+
227
+ query_params = request_dict.get('_query')
228
+ if query_params:
229
+ path = f'{path}?{urlencode(query_params)}'
230
+ # TODO: remove the hack that pops config.
231
+
232
+ request_dict.pop('config', None)
233
+
234
+ # Token creation request data need to replace 'setup' with
235
+ # 'bidiGenerateContentSetup'
236
+ if request_dict:
237
+ request_dict = _convert_bidi_setup_to_token_setup(request_dict, config)
238
+
239
+ http_options: Optional[types.HttpOptions] = None
240
+ if (
241
+ parameter_model is not None
242
+ and parameter_model.config is not None
243
+ and parameter_model.config.http_options is not None
244
+ ):
245
+ http_options = parameter_model.config.http_options
246
+
247
+ request_dict = _common.convert_to_dict(request_dict)
248
+ request_dict = _common.encode_unserializable_types(request_dict)
249
+
250
+ response_dict = self._api_client.request(
251
+ 'post', path, request_dict, http_options
252
+ )
253
+
254
+ if not self._api_client.vertexai:
255
+ response_dict = tokens_converters._AuthToken_from_mldev(
256
+ self._api_client, response_dict
257
+ )
258
+
259
+ return_value = types.AuthToken._from_response(
260
+ response=response_dict, kwargs=parameter_model.model_dump()
261
+ )
262
+ self._api_client._verify_response(return_value)
263
+ return return_value
264
+
265
+
266
+ class AsyncTokens(_api_module.BaseModule):
267
+ """[Experimental] Async Auth Tokens API client.
268
+
269
+ This class provides asynchronous methods for creating auth tokens.
270
+ """
271
+
272
+ @_common.experimental_warning(
273
+ "The SDK's token creation implementation is experimental, "
274
+ 'and may change in future versions.',
275
+ )
276
+ async def create(
277
+ self, *, config: Optional[types.CreateAuthTokenConfigOrDict] = None
278
+ ) -> types.AuthToken:
279
+ """Creates an auth token asynchronously.
280
+
281
+ Args:
282
+ config (CreateAuthTokenConfig): Optional configuration for the request.
283
+
284
+ Usage:
285
+
286
+ .. code-block:: python
287
+
288
+ auth_token = await client.aio.tokens.create(
289
+ config=types.CreateAuthTokenConfig(
290
+ uses=10,
291
+ live_constrained_parameters=types.LiveEphemeralParameters(
292
+ model='gemini-2.0-flash-live-001',
293
+ config=types.LiveConnectConfig(
294
+ system_instruction='You are an LLM called Gemini.'
295
+ ),
296
+ ),
297
+ )
298
+ )
299
+ """
300
+
301
+ parameter_model = types.CreateAuthTokenParameters(
302
+ config=config,
303
+ )
304
+
305
+ request_url_dict: Optional[dict[str, str]]
306
+ if self._api_client.vertexai:
307
+ raise ValueError(
308
+ 'This method is only supported in the Gemini Developer client.'
309
+ )
310
+ else:
311
+ request_dict = tokens_converters._CreateAuthTokenParameters_to_mldev(
312
+ self._api_client, parameter_model
313
+ )
314
+ request_url_dict = request_dict.get('_url')
315
+ if request_url_dict:
316
+ path = 'auth_tokens'.format_map(request_url_dict)
317
+ else:
318
+ path = 'auth_tokens'
319
+
320
+ query_params = request_dict.get('_query')
321
+ if query_params:
322
+ path = f'{path}?{urlencode(query_params)}'
323
+ # TODO: remove the hack that pops config.
324
+ request_dict.pop('config', None)
325
+
326
+ # Token creation request data need to replace 'setup' with
327
+ # 'bidiGenerateContentSetup'
328
+ request_dict = _convert_bidi_setup_to_token_setup(request_dict, config)
329
+
330
+ http_options: Optional[types.HttpOptions] = None
331
+ if (
332
+ parameter_model is not None
333
+ and parameter_model.config is not None
334
+ and parameter_model.config.http_options is not None
335
+ ):
336
+ http_options = parameter_model.config.http_options
337
+
338
+ request_dict = _common.convert_to_dict(request_dict)
339
+ request_dict = _common.encode_unserializable_types(request_dict)
340
+
341
+ response_dict = await self._api_client.async_request(
342
+ 'post',
343
+ path,
344
+ request_dict,
345
+ http_options=http_options,
346
+ )
347
+
348
+ if not self._api_client.vertexai:
349
+ response_dict = tokens_converters._AuthToken_from_mldev(
350
+ self._api_client, response_dict
351
+ )
352
+
353
+ return_value = types.AuthToken._from_response(
354
+ response=response_dict, kwargs=parameter_model.model_dump()
355
+ )
356
+ self._api_client._verify_response(return_value)
357
+ return return_value