google-genai 1.15.0__py3-none-any.whl → 1.16.1__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/__init__.py +5 -3
- google/genai/_adapters.py +55 -0
- google/genai/_api_client.py +3 -3
- google/genai/_api_module.py +1 -1
- google/genai/_automatic_function_calling_util.py +1 -1
- google/genai/_common.py +1 -1
- google/genai/_extra_utils.py +114 -9
- google/genai/_live_converters.py +1295 -20
- google/genai/_mcp_utils.py +117 -0
- google/genai/_replay_api_client.py +1 -1
- google/genai/_test_api_client.py +1 -1
- google/genai/_tokens_converters.py +1701 -0
- google/genai/_transformers.py +66 -33
- google/genai/caches.py +223 -20
- google/genai/chats.py +1 -1
- google/genai/client.py +12 -1
- google/genai/errors.py +1 -1
- google/genai/live.py +218 -35
- google/genai/live_music.py +201 -0
- google/genai/models.py +505 -44
- google/genai/pagers.py +1 -1
- google/genai/tokens.py +357 -0
- google/genai/types.py +7887 -6765
- google/genai/version.py +2 -2
- {google_genai-1.15.0.dist-info → google_genai-1.16.1.dist-info}/METADATA +8 -4
- google_genai-1.16.1.dist-info/RECORD +35 -0
- {google_genai-1.15.0.dist-info → google_genai-1.16.1.dist-info}/WHEEL +1 -1
- google_genai-1.15.0.dist-info/RECORD +0 -30
- {google_genai-1.15.0.dist-info → google_genai-1.16.1.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.15.0.dist-info → google_genai-1.16.1.dist-info}/top_level.txt +0 -0
google/genai/pagers.py
CHANGED
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
|