google-genai 1.19.0__py3-none-any.whl → 1.21.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/_api_client.py +449 -137
- google/genai/_common.py +88 -1
- google/genai/_live_converters.py +174 -414
- google/genai/_replay_api_client.py +10 -9
- google/genai/_tokens_converters.py +81 -176
- google/genai/_transformers.py +19 -40
- google/genai/batches.py +47 -64
- google/genai/caches.py +132 -222
- google/genai/chats.py +9 -14
- google/genai/client.py +1 -1
- google/genai/errors.py +32 -6
- google/genai/files.py +89 -103
- google/genai/live.py +15 -20
- google/genai/live_music.py +4 -5
- google/genai/models.py +412 -558
- google/genai/operations.py +36 -68
- google/genai/tokens.py +11 -6
- google/genai/tunings.py +65 -113
- google/genai/types.py +305 -92
- google/genai/version.py +1 -1
- {google_genai-1.19.0.dist-info → google_genai-1.21.0.dist-info}/METADATA +47 -1
- google_genai-1.21.0.dist-info/RECORD +35 -0
- google_genai-1.19.0.dist-info/RECORD +0 -35
- {google_genai-1.19.0.dist-info → google_genai-1.21.0.dist-info}/WHEEL +0 -0
- {google_genai-1.19.0.dist-info → google_genai-1.21.0.dist-info}/licenses/LICENSE +0 -0
- {google_genai-1.19.0.dist-info → google_genai-1.21.0.dist-info}/top_level.txt +0 -0
google/genai/_common.py
CHANGED
@@ -19,6 +19,7 @@ import base64
|
|
19
19
|
import datetime
|
20
20
|
import enum
|
21
21
|
import functools
|
22
|
+
import logging
|
22
23
|
import typing
|
23
24
|
from typing import Any, Callable, Optional, Union, get_origin, get_args
|
24
25
|
import uuid
|
@@ -30,6 +31,7 @@ from pydantic import alias_generators
|
|
30
31
|
from . import _api_client
|
31
32
|
from . import errors
|
32
33
|
|
34
|
+
logger = logging.getLogger('google_genai._common')
|
33
35
|
|
34
36
|
def set_value_by_path(data: Optional[dict[Any, Any]], keys: list[str], value: Any) -> None:
|
35
37
|
"""Examples:
|
@@ -253,7 +255,21 @@ class BaseModel(pydantic.BaseModel):
|
|
253
255
|
# To maintain forward compatibility, we need to remove extra fields from
|
254
256
|
# the response.
|
255
257
|
# We will provide another mechanism to allow users to access these fields.
|
256
|
-
|
258
|
+
|
259
|
+
# For Agent Engine we don't want to call _remove_all_fields because the
|
260
|
+
# user may pass a dict that is not a subclass of BaseModel.
|
261
|
+
# If more modules require we skip this, we may want a different approach
|
262
|
+
should_skip_removing_fields = (
|
263
|
+
kwargs is not None and
|
264
|
+
'config' in kwargs and
|
265
|
+
kwargs['config'] is not None and
|
266
|
+
isinstance(kwargs['config'], dict) and
|
267
|
+
'include_all_fields' in kwargs['config']
|
268
|
+
and kwargs['config']['include_all_fields']
|
269
|
+
)
|
270
|
+
|
271
|
+
if not should_skip_removing_fields:
|
272
|
+
_remove_extra_fields(cls, response)
|
257
273
|
validated_response = cls.model_validate(response)
|
258
274
|
return validated_response
|
259
275
|
|
@@ -351,3 +367,74 @@ def experimental_warning(message: str) -> Callable[[Callable[..., Any]], Callabl
|
|
351
367
|
return wrapper
|
352
368
|
return decorator
|
353
369
|
|
370
|
+
|
371
|
+
def _normalize_key_for_matching(key_str: str) -> str:
|
372
|
+
"""Normalizes a key for case-insensitive and snake/camel matching."""
|
373
|
+
return key_str.replace("_", "").lower()
|
374
|
+
|
375
|
+
|
376
|
+
def align_key_case(target_dict: dict[str, Any], update_dict: dict[str, Any]) -> dict[str, Any]:
|
377
|
+
"""Aligns the keys of update_dict to the case of target_dict keys.
|
378
|
+
|
379
|
+
Args:
|
380
|
+
target_dict: The dictionary with the target key casing.
|
381
|
+
update_dict: The dictionary whose keys need to be aligned.
|
382
|
+
|
383
|
+
Returns:
|
384
|
+
A new dictionary with keys aligned to target_dict's key casing.
|
385
|
+
"""
|
386
|
+
aligned_update_dict: dict[str, Any] = {}
|
387
|
+
target_keys_map = {_normalize_key_for_matching(key): key for key in target_dict.keys()}
|
388
|
+
|
389
|
+
for key, value in update_dict.items():
|
390
|
+
normalized_update_key = _normalize_key_for_matching(key)
|
391
|
+
|
392
|
+
if normalized_update_key in target_keys_map:
|
393
|
+
aligned_key = target_keys_map[normalized_update_key]
|
394
|
+
else:
|
395
|
+
aligned_key = key
|
396
|
+
|
397
|
+
if isinstance(value, dict) and isinstance(target_dict.get(aligned_key), dict):
|
398
|
+
aligned_update_dict[aligned_key] = align_key_case(target_dict[aligned_key], value)
|
399
|
+
elif isinstance(value, list) and isinstance(target_dict.get(aligned_key), list):
|
400
|
+
# Direct assign as we treat update_dict list values as golden source.
|
401
|
+
aligned_update_dict[aligned_key] = value
|
402
|
+
else:
|
403
|
+
aligned_update_dict[aligned_key] = value
|
404
|
+
return aligned_update_dict
|
405
|
+
|
406
|
+
|
407
|
+
def recursive_dict_update(
|
408
|
+
target_dict: dict[str, Any], update_dict: dict[str, Any]
|
409
|
+
) -> None:
|
410
|
+
"""Recursively updates a target dictionary with values from an update dictionary.
|
411
|
+
|
412
|
+
We don't enforce the updated dict values to have the same type with the
|
413
|
+
target_dict values except log warnings.
|
414
|
+
Users providing the update_dict should be responsible for constructing correct
|
415
|
+
data.
|
416
|
+
|
417
|
+
Args:
|
418
|
+
target_dict (dict): The dictionary to be updated.
|
419
|
+
update_dict (dict): The dictionary containing updates.
|
420
|
+
"""
|
421
|
+
# Python SDK http request may change in camel case or snake case:
|
422
|
+
# If the field is directly set via setv() function, then it is camel case;
|
423
|
+
# otherwise it is snake case.
|
424
|
+
# Align the update_dict key case to target_dict to ensure correct dict update.
|
425
|
+
aligned_update_dict = align_key_case(target_dict, update_dict)
|
426
|
+
for key, value in aligned_update_dict.items():
|
427
|
+
if (
|
428
|
+
key in target_dict
|
429
|
+
and isinstance(target_dict[key], dict)
|
430
|
+
and isinstance(value, dict)
|
431
|
+
):
|
432
|
+
recursive_dict_update(target_dict[key], value)
|
433
|
+
elif key in target_dict and not isinstance(target_dict[key], type(value)):
|
434
|
+
logger.warning(
|
435
|
+
f"Type mismatch for key '{key}'. Existing type:"
|
436
|
+
f' {type(target_dict[key])}, new type: {type(value)}. Overwriting.'
|
437
|
+
)
|
438
|
+
target_dict[key] = value
|
439
|
+
else:
|
440
|
+
target_dict[key] = value
|