google-genai 1.27.0__py3-none-any.whl → 1.28.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/__init__.py CHANGED
@@ -15,6 +15,7 @@
15
15
 
16
16
  """Google Gen AI SDK"""
17
17
 
18
+ from . import types
18
19
  from . import version
19
20
  from .client import Client
20
21
 
@@ -32,6 +32,7 @@ import logging
32
32
  import math
33
33
  import os
34
34
  import ssl
35
+ import random
35
36
  import sys
36
37
  import threading
37
38
  import time
@@ -81,6 +82,7 @@ if TYPE_CHECKING:
81
82
 
82
83
  logger = logging.getLogger('google_genai._api_client')
83
84
  CHUNK_SIZE = 8 * 1024 * 1024 # 8 MB chunk size
85
+ READ_BUFFER_SIZE = 2**20
84
86
  MAX_RETRY_COUNT = 3
85
87
  INITIAL_RETRY_DELAY = 1 # second
86
88
  DELAY_MULTIPLIER = 2
@@ -363,7 +365,7 @@ _RETRY_HTTP_STATUS_CODES = (
363
365
  )
364
366
 
365
367
 
366
- def _retry_args(options: Optional[HttpRetryOptions]) -> dict[str, Any]:
368
+ def _retry_args(options: Optional[HttpRetryOptions]) -> _common.StringDict:
367
369
  """Returns the retry args for the given http retry options.
368
370
 
369
371
  Args:
@@ -533,17 +535,30 @@ class BaseApiClient:
533
535
  + ' precedence over the API key from the environment variables.'
534
536
  )
535
537
  self.api_key = None
536
- if not self.project and not self.api_key:
538
+
539
+ # Skip fetching project from ADC if base url is provided in http options.
540
+ if (
541
+ not self.project
542
+ and not self.api_key
543
+ and not validated_http_options.base_url
544
+ ):
537
545
  credentials, self.project = _load_auth(project=None)
538
546
  if not self._credentials:
539
547
  self._credentials = credentials
540
- if not ((self.project and self.location) or self.api_key):
548
+
549
+ has_sufficient_auth = (self.project and self.location) or self.api_key
550
+
551
+ if (not has_sufficient_auth and not validated_http_options.base_url):
552
+ # Skip sufficient auth check if base url is provided in http options.
541
553
  raise ValueError(
542
554
  'Project and location or API key must be set when using the Vertex '
543
555
  'AI API.'
544
556
  )
545
557
  if self.api_key or self.location == 'global':
546
558
  self._http_options.base_url = f'https://aiplatform.googleapis.com/'
559
+ elif validated_http_options.base_url and not has_sufficient_auth:
560
+ # Avoid setting default base url and api version if base_url provided.
561
+ self._http_options.base_url = validated_http_options.base_url
547
562
  else:
548
563
  self._http_options.base_url = (
549
564
  f'https://{self.location}-aiplatform.googleapis.com/'
@@ -592,7 +607,7 @@ class BaseApiClient:
592
607
  @staticmethod
593
608
  def _ensure_httpx_ssl_ctx(
594
609
  options: HttpOptions,
595
- ) -> Tuple[dict[str, Any], dict[str, Any]]:
610
+ ) -> Tuple[_common.StringDict, _common.StringDict]:
596
611
  """Ensures the SSL context is present in the HTTPX client args.
597
612
 
598
613
  Creates a default SSL context if one is not provided.
@@ -626,9 +641,9 @@ class BaseApiClient:
626
641
  )
627
642
 
628
643
  def _maybe_set(
629
- args: Optional[dict[str, Any]],
644
+ args: Optional[_common.StringDict],
630
645
  ctx: ssl.SSLContext,
631
- ) -> dict[str, Any]:
646
+ ) -> _common.StringDict:
632
647
  """Sets the SSL context in the client args if not set.
633
648
 
634
649
  Does not override the SSL context if it is already set.
@@ -656,7 +671,7 @@ class BaseApiClient:
656
671
  )
657
672
 
658
673
  @staticmethod
659
- def _ensure_aiohttp_ssl_ctx(options: HttpOptions) -> dict[str, Any]:
674
+ def _ensure_aiohttp_ssl_ctx(options: HttpOptions) -> _common.StringDict:
660
675
  """Ensures the SSL context is present in the async client args.
661
676
 
662
677
  Creates a default SSL context if one is not provided.
@@ -684,9 +699,9 @@ class BaseApiClient:
684
699
  )
685
700
 
686
701
  def _maybe_set(
687
- args: Optional[dict[str, Any]],
702
+ args: Optional[_common.StringDict],
688
703
  ctx: ssl.SSLContext,
689
- ) -> dict[str, Any]:
704
+ ) -> _common.StringDict:
690
705
  """Sets the SSL context in the client args if not set.
691
706
 
692
707
  Does not override the SSL context if it is already set.
@@ -714,7 +729,7 @@ class BaseApiClient:
714
729
  return _maybe_set(async_args, ctx)
715
730
 
716
731
  @staticmethod
717
- def _ensure_websocket_ssl_ctx(options: HttpOptions) -> dict[str, Any]:
732
+ def _ensure_websocket_ssl_ctx(options: HttpOptions) -> _common.StringDict:
718
733
  """Ensures the SSL context is present in the async client args.
719
734
 
720
735
  Creates a default SSL context if one is not provided.
@@ -742,9 +757,9 @@ class BaseApiClient:
742
757
  )
743
758
 
744
759
  def _maybe_set(
745
- args: Optional[dict[str, Any]],
760
+ args: Optional[_common.StringDict],
746
761
  ctx: ssl.SSLContext,
747
- ) -> dict[str, Any]:
762
+ ) -> _common.StringDict:
748
763
  """Sets the SSL context in the client args if not set.
749
764
 
750
765
  Does not override the SSL context if it is already set.
@@ -864,7 +879,7 @@ class BaseApiClient:
864
879
  self.vertexai
865
880
  and not path.startswith('projects/')
866
881
  and not query_vertex_base_models
867
- and not self.api_key
882
+ and (self.project or self.location)
868
883
  ):
869
884
  path = f'projects/{self.project}/locations/{self.location}/' + path
870
885
 
@@ -920,7 +935,8 @@ class BaseApiClient:
920
935
  stream: bool = False,
921
936
  ) -> HttpResponse:
922
937
  data: Optional[Union[str, bytes]] = None
923
- if self.vertexai and not self.api_key:
938
+ # If using proj/location, fetch ADC
939
+ if self.vertexai and (self.project or self.location):
924
940
  http_request.headers['Authorization'] = f'Bearer {self._access_token()}'
925
941
  if self._credentials and self._credentials.quota_project_id:
926
942
  http_request.headers['x-goog-user-project'] = (
@@ -963,8 +979,21 @@ class BaseApiClient:
963
979
  def _request(
964
980
  self,
965
981
  http_request: HttpRequest,
982
+ http_options: Optional[HttpOptionsOrDict] = None,
966
983
  stream: bool = False,
967
984
  ) -> HttpResponse:
985
+ if http_options:
986
+ parameter_model = (
987
+ HttpOptions(**http_options)
988
+ if isinstance(http_options, dict)
989
+ else http_options
990
+ )
991
+ # Support per request retry options.
992
+ if parameter_model.retry_options:
993
+ retry_kwargs = _retry_args(parameter_model.retry_options)
994
+ retry = tenacity.Retrying(**retry_kwargs)
995
+ return retry(self._request_once, http_request, stream) # type: ignore[no-any-return]
996
+
968
997
  return self._retry(self._request_once, http_request, stream) # type: ignore[no-any-return]
969
998
 
970
999
  async def _async_request_once(
@@ -972,7 +1001,8 @@ class BaseApiClient:
972
1001
  ) -> HttpResponse:
973
1002
  data: Optional[Union[str, bytes]] = None
974
1003
 
975
- if self.vertexai and not self.api_key:
1004
+ # If using proj/location, fetch ADC
1005
+ if self.vertexai and (self.project or self.location):
976
1006
  http_request.headers['Authorization'] = (
977
1007
  f'Bearer {await self._async_access_token()}'
978
1008
  )
@@ -993,15 +1023,43 @@ class BaseApiClient:
993
1023
  session = aiohttp.ClientSession(
994
1024
  headers=http_request.headers,
995
1025
  trust_env=True,
1026
+ read_bufsize=READ_BUFFER_SIZE,
996
1027
  )
997
- response = await session.request(
998
- method=http_request.method,
999
- url=http_request.url,
1000
- headers=http_request.headers,
1001
- data=data,
1002
- timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
1003
- **self._async_client_session_request_args,
1004
- )
1028
+ try:
1029
+ response = await session.request(
1030
+ method=http_request.method,
1031
+ url=http_request.url,
1032
+ headers=http_request.headers,
1033
+ data=data,
1034
+ timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
1035
+ **self._async_client_session_request_args,
1036
+ )
1037
+ except (
1038
+ aiohttp.ClientConnectorError,
1039
+ aiohttp.ClientConnectorDNSError,
1040
+ aiohttp.ClientOSError,
1041
+ aiohttp.ServerDisconnectedError,
1042
+ ) as e:
1043
+ await asyncio.sleep(1 + random.randint(0, 9))
1044
+ logger.info('Retrying due to aiohttp error: %s' % e)
1045
+ # Retrieve the SSL context from the session.
1046
+ self._async_client_session_request_args = (
1047
+ self._ensure_aiohttp_ssl_ctx(self._http_options)
1048
+ )
1049
+ # Instantiate a new session with the updated SSL context.
1050
+ session = aiohttp.ClientSession(
1051
+ headers=http_request.headers,
1052
+ trust_env=True,
1053
+ read_bufsize=READ_BUFFER_SIZE,
1054
+ )
1055
+ response = await session.request(
1056
+ method=http_request.method,
1057
+ url=http_request.url,
1058
+ headers=http_request.headers,
1059
+ data=data,
1060
+ timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
1061
+ **self._async_client_session_request_args,
1062
+ )
1005
1063
 
1006
1064
  await errors.APIError.raise_for_async_response(response)
1007
1065
  return HttpResponse(response.headers, response, session=session)
@@ -1022,20 +1080,50 @@ class BaseApiClient:
1022
1080
  return HttpResponse(client_response.headers, client_response)
1023
1081
  else:
1024
1082
  if self._use_aiohttp():
1025
- async with aiohttp.ClientSession(
1026
- headers=http_request.headers,
1027
- trust_env=True,
1028
- ) as session:
1029
- response = await session.request(
1030
- method=http_request.method,
1031
- url=http_request.url,
1083
+ try:
1084
+ async with aiohttp.ClientSession(
1032
1085
  headers=http_request.headers,
1033
- data=data,
1034
- timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
1035
- **self._async_client_session_request_args,
1086
+ trust_env=True,
1087
+ read_bufsize=READ_BUFFER_SIZE,
1088
+ ) as session:
1089
+ response = await session.request(
1090
+ method=http_request.method,
1091
+ url=http_request.url,
1092
+ headers=http_request.headers,
1093
+ data=data,
1094
+ timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
1095
+ **self._async_client_session_request_args,
1096
+ )
1097
+ await errors.APIError.raise_for_async_response(response)
1098
+ return HttpResponse(response.headers, [await response.text()])
1099
+ except (
1100
+ aiohttp.ClientConnectorError,
1101
+ aiohttp.ClientConnectorDNSError,
1102
+ aiohttp.ClientOSError,
1103
+ aiohttp.ServerDisconnectedError,
1104
+ ) as e:
1105
+ await asyncio.sleep(1 + random.randint(0, 9))
1106
+ logger.info('Retrying due to aiohttp error: %s' % e)
1107
+ # Retrieve the SSL context from the session.
1108
+ self._async_client_session_request_args = (
1109
+ self._ensure_aiohttp_ssl_ctx(self._http_options)
1036
1110
  )
1037
- await errors.APIError.raise_for_async_response(response)
1038
- return HttpResponse(response.headers, [await response.text()])
1111
+ # Instantiate a new session with the updated SSL context.
1112
+ async with aiohttp.ClientSession(
1113
+ headers=http_request.headers,
1114
+ trust_env=True,
1115
+ read_bufsize=READ_BUFFER_SIZE,
1116
+ ) as session:
1117
+ response = await session.request(
1118
+ method=http_request.method,
1119
+ url=http_request.url,
1120
+ headers=http_request.headers,
1121
+ data=data,
1122
+ timeout=aiohttp.ClientTimeout(connect=http_request.timeout),
1123
+ **self._async_client_session_request_args,
1124
+ )
1125
+ await errors.APIError.raise_for_async_response(response)
1126
+ return HttpResponse(response.headers, [await response.text()])
1039
1127
  else:
1040
1128
  # aiohttp is not available. Fall back to httpx.
1041
1129
  client_response = await self._async_httpx_client.request(
@@ -1051,13 +1139,25 @@ class BaseApiClient:
1051
1139
  async def _async_request(
1052
1140
  self,
1053
1141
  http_request: HttpRequest,
1142
+ http_options: Optional[HttpOptionsOrDict] = None,
1054
1143
  stream: bool = False,
1055
1144
  ) -> HttpResponse:
1145
+ if http_options:
1146
+ parameter_model = (
1147
+ HttpOptions(**http_options)
1148
+ if isinstance(http_options, dict)
1149
+ else http_options
1150
+ )
1151
+ # Support per request retry options.
1152
+ if parameter_model.retry_options:
1153
+ retry_kwargs = _retry_args(parameter_model.retry_options)
1154
+ retry = tenacity.AsyncRetrying(**retry_kwargs)
1155
+ return await retry(self._async_request_once, http_request, stream) # type: ignore[no-any-return]
1056
1156
  return await self._async_retry( # type: ignore[no-any-return]
1057
1157
  self._async_request_once, http_request, stream
1058
1158
  )
1059
1159
 
1060
- def get_read_only_http_options(self) -> dict[str, Any]:
1160
+ def get_read_only_http_options(self) -> _common.StringDict:
1061
1161
  if isinstance(self._http_options, BaseModel):
1062
1162
  copied = self._http_options.model_dump()
1063
1163
  else:
@@ -1074,7 +1174,7 @@ class BaseApiClient:
1074
1174
  http_request = self._build_request(
1075
1175
  http_method, path, request_dict, http_options
1076
1176
  )
1077
- response = self._request(http_request, stream=False)
1177
+ response = self._request(http_request, http_options, stream=False)
1078
1178
  response_body = (
1079
1179
  response.response_stream[0] if response.response_stream else ''
1080
1180
  )
@@ -1091,7 +1191,7 @@ class BaseApiClient:
1091
1191
  http_method, path, request_dict, http_options
1092
1192
  )
1093
1193
 
1094
- session_response = self._request(http_request, stream=True)
1194
+ session_response = self._request(http_request, http_options, stream=True)
1095
1195
  for chunk in session_response.segments():
1096
1196
  yield SdkHttpResponse(
1097
1197
  headers=session_response.headers, body=json.dumps(chunk)
@@ -1108,7 +1208,9 @@ class BaseApiClient:
1108
1208
  http_method, path, request_dict, http_options
1109
1209
  )
1110
1210
 
1111
- result = await self._async_request(http_request=http_request, stream=False)
1211
+ result = await self._async_request(
1212
+ http_request=http_request, http_options=http_options, stream=False
1213
+ )
1112
1214
  response_body = result.response_stream[0] if result.response_stream else ''
1113
1215
  return SdkHttpResponse(headers=result.headers, body=response_body)
1114
1216
 
@@ -1340,6 +1442,7 @@ class BaseApiClient:
1340
1442
  async with aiohttp.ClientSession(
1341
1443
  headers=self._http_options.headers,
1342
1444
  trust_env=True,
1445
+ read_bufsize=READ_BUFFER_SIZE,
1343
1446
  ) as session:
1344
1447
  while True:
1345
1448
  if isinstance(file, io.IOBase):
@@ -1523,6 +1626,7 @@ class BaseApiClient:
1523
1626
  async with aiohttp.ClientSession(
1524
1627
  headers=http_request.headers,
1525
1628
  trust_env=True,
1629
+ read_bufsize=READ_BUFFER_SIZE,
1526
1630
  ) as session:
1527
1631
  response = await session.request(
1528
1632
  method=http_request.method,
google/genai/_common.py CHANGED
@@ -22,15 +22,17 @@ import enum
22
22
  import functools
23
23
  import logging
24
24
  import typing
25
- from typing import Any, Callable, Optional, FrozenSet, Union, get_args, get_origin
25
+ from typing import Any, Callable, FrozenSet, Optional, Union, get_args, get_origin
26
26
  import uuid
27
27
  import warnings
28
-
29
28
  import pydantic
30
29
  from pydantic import alias_generators
30
+ from typing_extensions import TypeAlias
31
31
 
32
32
  logger = logging.getLogger('google_genai._common')
33
33
 
34
+ StringDict: TypeAlias = dict[str, Any]
35
+
34
36
 
35
37
  class ExperimentalWarning(Warning):
36
38
  """Warning for experimental features."""
@@ -355,7 +357,6 @@ def _pretty_repr(
355
357
  return raw_repr.replace('\n', f'\n{next_indent_str}')
356
358
 
357
359
 
358
-
359
360
  def _format_collection(
360
361
  obj: Any,
361
362
  *,
@@ -555,7 +556,9 @@ def _normalize_key_for_matching(key_str: str) -> str:
555
556
  return key_str.replace("_", "").lower()
556
557
 
557
558
 
558
- def align_key_case(target_dict: dict[str, Any], update_dict: dict[str, Any]) -> dict[str, Any]:
559
+ def align_key_case(
560
+ target_dict: StringDict, update_dict: StringDict
561
+ ) -> StringDict:
559
562
  """Aligns the keys of update_dict to the case of target_dict keys.
560
563
 
561
564
  Args:
@@ -565,7 +568,7 @@ def align_key_case(target_dict: dict[str, Any], update_dict: dict[str, Any]) ->
565
568
  Returns:
566
569
  A new dictionary with keys aligned to target_dict's key casing.
567
570
  """
568
- aligned_update_dict: dict[str, Any] = {}
571
+ aligned_update_dict: StringDict = {}
569
572
  target_keys_map = {_normalize_key_for_matching(key): key for key in target_dict.keys()}
570
573
 
571
574
  for key, value in update_dict.items():
@@ -587,7 +590,7 @@ def align_key_case(target_dict: dict[str, Any], update_dict: dict[str, Any]) ->
587
590
 
588
591
 
589
592
  def recursive_dict_update(
590
- target_dict: dict[str, Any], update_dict: dict[str, Any]
593
+ target_dict: StringDict, update_dict: StringDict
591
594
  ) -> None:
592
595
  """Recursively updates a target dictionary with values from an update dictionary.
593
596
 
@@ -155,8 +155,8 @@ def get_function_map(
155
155
 
156
156
 
157
157
  def convert_number_values_for_dict_function_call_args(
158
- args: dict[str, Any],
159
- ) -> dict[str, Any]:
158
+ args: _common.StringDict,
159
+ ) -> _common.StringDict:
160
160
  """Converts float values in dict with no decimal to integers."""
161
161
  return {
162
162
  key: convert_number_values_for_function_call_args(value)
@@ -257,8 +257,8 @@ def convert_if_exist_pydantic_model(
257
257
 
258
258
 
259
259
  def convert_argument_from_function(
260
- args: dict[str, Any], function: Callable[..., Any]
261
- ) -> dict[str, Any]:
260
+ args: _common.StringDict, function: Callable[..., Any]
261
+ ) -> _common.StringDict:
262
262
  signature = inspect.signature(function)
263
263
  func_name = function.__name__
264
264
  converted_args = {}
@@ -274,7 +274,7 @@ def convert_argument_from_function(
274
274
 
275
275
 
276
276
  def invoke_function_from_dict_args(
277
- args: Dict[str, Any], function_to_invoke: Callable[..., Any]
277
+ args: _common.StringDict, function_to_invoke: Callable[..., Any]
278
278
  ) -> Any:
279
279
  converted_args = convert_argument_from_function(args, function_to_invoke)
280
280
  try:
@@ -288,7 +288,7 @@ def invoke_function_from_dict_args(
288
288
 
289
289
 
290
290
  async def invoke_function_from_dict_args_async(
291
- args: Dict[str, Any], function_to_invoke: Callable[..., Any]
291
+ args: _common.StringDict, function_to_invoke: Callable[..., Any]
292
292
  ) -> Any:
293
293
  converted_args = convert_argument_from_function(args, function_to_invoke)
294
294
  try:
@@ -321,7 +321,7 @@ def get_function_response_parts(
321
321
  args = convert_number_values_for_dict_function_call_args(
322
322
  part.function_call.args
323
323
  )
324
- func_response: dict[str, Any]
324
+ func_response: _common.StringDict
325
325
  try:
326
326
  if not isinstance(func, McpToGenAiToolAdapter):
327
327
  func_response = {
@@ -356,7 +356,7 @@ async def get_function_response_parts_async(
356
356
  args = convert_number_values_for_dict_function_call_args(
357
357
  part.function_call.args
358
358
  )
359
- func_response: dict[str, Any]
359
+ func_response: _common.StringDict
360
360
  try:
361
361
  if isinstance(func, McpToGenAiToolAdapter):
362
362
  mcp_tool_response = await func.call_tool(
@@ -19,6 +19,7 @@ from importlib.metadata import PackageNotFoundError, version
19
19
  import typing
20
20
  from typing import Any
21
21
 
22
+ from . import _common
22
23
  from . import types
23
24
 
24
25
  if typing.TYPE_CHECKING:
@@ -89,7 +90,9 @@ def set_mcp_usage_header(headers: dict[str, str]) -> None:
89
90
  ).lstrip()
90
91
 
91
92
 
92
- def _filter_to_supported_schema(schema: dict[str, Any]) -> dict[str, Any]:
93
+ def _filter_to_supported_schema(
94
+ schema: _common.StringDict,
95
+ ) -> _common.StringDict:
93
96
  """Filters the schema to only include fields that are supported by JSONSchema."""
94
97
  supported_fields: set[str] = set(types.JSONSchema.model_fields.keys())
95
98
  schema_field_names: tuple[str] = ("items",) # 'additional_properties' to come
@@ -479,13 +479,14 @@ class ReplayApiClient(BaseApiClient):
479
479
  def _request(
480
480
  self,
481
481
  http_request: HttpRequest,
482
+ http_options: Optional[HttpOptionsOrDict] = None,
482
483
  stream: bool = False,
483
484
  ) -> HttpResponse:
484
485
  self._initialize_replay_session_if_not_loaded()
485
486
  if self._should_call_api():
486
487
  _debug_print('api mode request: %s' % http_request)
487
488
  try:
488
- result = super()._request(http_request, stream)
489
+ result = super()._request(http_request, http_options, stream)
489
490
  except errors.APIError as e:
490
491
  self._record_interaction(http_request, e)
491
492
  raise e
@@ -507,13 +508,16 @@ class ReplayApiClient(BaseApiClient):
507
508
  async def _async_request(
508
509
  self,
509
510
  http_request: HttpRequest,
511
+ http_options: Optional[HttpOptionsOrDict] = None,
510
512
  stream: bool = False,
511
513
  ) -> HttpResponse:
512
514
  self._initialize_replay_session_if_not_loaded()
513
515
  if self._should_call_api():
514
516
  _debug_print('api mode request: %s' % http_request)
515
517
  try:
516
- result = await super()._async_request(http_request, stream)
518
+ result = await super()._async_request(
519
+ http_request, http_options, stream
520
+ )
517
521
  except errors.APIError as e:
518
522
  self._record_interaction(http_request, e)
519
523
  raise e
@@ -35,6 +35,7 @@ if typing.TYPE_CHECKING:
35
35
  import pydantic
36
36
 
37
37
  from . import _api_client
38
+ from . import _common
38
39
  from . import types
39
40
 
40
41
  logger = logging.getLogger('google_genai._transformers')
@@ -195,20 +196,20 @@ def t_models_url(
195
196
 
196
197
 
197
198
  def t_extract_models(
198
- response: dict[str, Any],
199
- ) -> list[dict[str, Any]]:
199
+ response: _common.StringDict,
200
+ ) -> list[_common.StringDict]:
200
201
  if not response:
201
202
  return []
202
203
 
203
- models: Optional[list[dict[str, Any]]] = response.get('models')
204
+ models: Optional[list[_common.StringDict]] = response.get('models')
204
205
  if models is not None:
205
206
  return models
206
207
 
207
- tuned_models: Optional[list[dict[str, Any]]] = response.get('tunedModels')
208
+ tuned_models: Optional[list[_common.StringDict]] = response.get('tunedModels')
208
209
  if tuned_models is not None:
209
210
  return tuned_models
210
211
 
211
- publisher_models: Optional[list[dict[str, Any]]] = response.get(
212
+ publisher_models: Optional[list[_common.StringDict]] = response.get(
212
213
  'publisherModels'
213
214
  )
214
215
  if publisher_models is not None:
@@ -560,7 +561,7 @@ def t_contents(
560
561
  return result
561
562
 
562
563
 
563
- def handle_null_fields(schema: dict[str, Any]) -> None:
564
+ def handle_null_fields(schema: _common.StringDict) -> None:
564
565
  """Process null fields in the schema so it is compatible with OpenAPI.
565
566
 
566
567
  The OpenAPI spec does not support 'type: 'null' in the schema. This function
@@ -639,9 +640,9 @@ def _raise_for_unsupported_mldev_properties(
639
640
 
640
641
 
641
642
  def process_schema(
642
- schema: dict[str, Any],
643
+ schema: _common.StringDict,
643
644
  client: Optional[_api_client.BaseApiClient],
644
- defs: Optional[dict[str, Any]] = None,
645
+ defs: Optional[_common.StringDict] = None,
645
646
  *,
646
647
  order_properties: bool = True,
647
648
  ) -> None:
@@ -740,7 +741,7 @@ def process_schema(
740
741
  if (ref := schema.pop('$ref', None)) is not None:
741
742
  schema.update(defs[ref.split('defs/')[-1]])
742
743
 
743
- def _recurse(sub_schema: dict[str, Any]) -> dict[str, Any]:
744
+ def _recurse(sub_schema: _common.StringDict) -> _common.StringDict:
744
745
  """Returns the processed `sub_schema`, resolving its '$ref' if any."""
745
746
  if (ref := sub_schema.pop('$ref', None)) is not None:
746
747
  sub_schema = defs[ref.split('defs/')[-1]]
@@ -820,7 +821,7 @@ def _process_enum(
820
821
 
821
822
  def _is_type_dict_str_any(
822
823
  origin: Union[types.SchemaUnionDict, Any],
823
- ) -> TypeGuard[dict[str, Any]]:
824
+ ) -> TypeGuard[_common.StringDict]:
824
825
  """Verifies the schema is of type dict[str, Any] for mypy type checking."""
825
826
  return isinstance(origin, dict) and all(
826
827
  isinstance(key, str) for key in origin
@@ -1075,10 +1076,10 @@ LRO_POLLING_MULTIPLIER = 1.5
1075
1076
 
1076
1077
 
1077
1078
  def t_resolve_operation(
1078
- api_client: _api_client.BaseApiClient, struct: dict[str, Any]
1079
+ api_client: _api_client.BaseApiClient, struct: _common.StringDict
1079
1080
  ) -> Any:
1080
1081
  if (name := struct.get('name')) and '/operations/' in name:
1081
- operation: dict[str, Any] = struct
1082
+ operation: _common.StringDict = struct
1082
1083
  total_seconds = 0.0
1083
1084
  delay_seconds = LRO_POLLING_INITIAL_DELAY_SECONDS
1084
1085
  while operation.get('done') != True:
google/genai/errors.py CHANGED
@@ -65,7 +65,7 @@ class APIError(Exception):
65
65
  'code', response_json.get('error', {}).get('code', None)
66
66
  )
67
67
 
68
- def _to_replay_record(self) -> dict[str, Any]:
68
+ def _to_replay_record(self) -> _common.StringDict:
69
69
  """Returns a dictionary representation of the error for replay recording.
70
70
 
71
71
  details is not included since it may expose internal information in the
google/genai/live.py CHANGED
@@ -33,7 +33,6 @@ from . import _common
33
33
  from . import _live_converters as live_converters
34
34
  from . import _mcp_utils
35
35
  from . import _transformers as t
36
- from . import client
37
36
  from . import errors
38
37
  from . import types
39
38
  from ._api_client import BaseApiClient
@@ -288,7 +287,7 @@ class AsyncSession:
288
287
  print(f'{msg.text}')
289
288
  ```
290
289
  """
291
- kwargs: dict[str, Any] = {}
290
+ kwargs: _common.StringDict = {}
292
291
  if media is not None:
293
292
  kwargs['media'] = media
294
293
  if audio is not None:
@@ -639,7 +638,7 @@ class AsyncSession:
639
638
  elif isinstance(formatted_input, Sequence) and any(
640
639
  isinstance(c, str) for c in formatted_input
641
640
  ):
642
- to_object: dict[str, Any] = {}
641
+ to_object: _common.StringDict = {}
643
642
  content_input_parts: list[types.PartUnion] = []
644
643
  for item in formatted_input:
645
644
  if isinstance(item, get_args(types.PartUnion)):
google/genai/models.py CHANGED
@@ -3549,6 +3549,11 @@ def _EmbedContentResponse_from_mldev(
3549
3549
  parent_object: Optional[dict[str, Any]] = None,
3550
3550
  ) -> dict[str, Any]:
3551
3551
  to_object: dict[str, Any] = {}
3552
+ if getv(from_object, ['sdkHttpResponse']) is not None:
3553
+ setv(
3554
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
3555
+ )
3556
+
3552
3557
  if getv(from_object, ['embeddings']) is not None:
3553
3558
  setv(
3554
3559
  to_object,
@@ -3647,6 +3652,11 @@ def _GenerateImagesResponse_from_mldev(
3647
3652
  parent_object: Optional[dict[str, Any]] = None,
3648
3653
  ) -> dict[str, Any]:
3649
3654
  to_object: dict[str, Any] = {}
3655
+ if getv(from_object, ['sdkHttpResponse']) is not None:
3656
+ setv(
3657
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
3658
+ )
3659
+
3650
3660
  if getv(from_object, ['predictions']) is not None:
3651
3661
  setv(
3652
3662
  to_object,
@@ -3772,6 +3782,11 @@ def _CountTokensResponse_from_mldev(
3772
3782
  parent_object: Optional[dict[str, Any]] = None,
3773
3783
  ) -> dict[str, Any]:
3774
3784
  to_object: dict[str, Any] = {}
3785
+ if getv(from_object, ['sdkHttpResponse']) is not None:
3786
+ setv(
3787
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
3788
+ )
3789
+
3775
3790
  if getv(from_object, ['totalTokens']) is not None:
3776
3791
  setv(to_object, ['total_tokens'], getv(from_object, ['totalTokens']))
3777
3792
 
@@ -4224,6 +4239,11 @@ def _EmbedContentResponse_from_vertex(
4224
4239
  parent_object: Optional[dict[str, Any]] = None,
4225
4240
  ) -> dict[str, Any]:
4226
4241
  to_object: dict[str, Any] = {}
4242
+ if getv(from_object, ['sdkHttpResponse']) is not None:
4243
+ setv(
4244
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
4245
+ )
4246
+
4227
4247
  if getv(from_object, ['predictions[]', 'embeddings']) is not None:
4228
4248
  setv(
4229
4249
  to_object,
@@ -4327,6 +4347,11 @@ def _GenerateImagesResponse_from_vertex(
4327
4347
  parent_object: Optional[dict[str, Any]] = None,
4328
4348
  ) -> dict[str, Any]:
4329
4349
  to_object: dict[str, Any] = {}
4350
+ if getv(from_object, ['sdkHttpResponse']) is not None:
4351
+ setv(
4352
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
4353
+ )
4354
+
4330
4355
  if getv(from_object, ['predictions']) is not None:
4331
4356
  setv(
4332
4357
  to_object,
@@ -4354,6 +4379,11 @@ def _EditImageResponse_from_vertex(
4354
4379
  parent_object: Optional[dict[str, Any]] = None,
4355
4380
  ) -> dict[str, Any]:
4356
4381
  to_object: dict[str, Any] = {}
4382
+ if getv(from_object, ['sdkHttpResponse']) is not None:
4383
+ setv(
4384
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
4385
+ )
4386
+
4357
4387
  if getv(from_object, ['predictions']) is not None:
4358
4388
  setv(
4359
4389
  to_object,
@@ -4372,6 +4402,11 @@ def _UpscaleImageResponse_from_vertex(
4372
4402
  parent_object: Optional[dict[str, Any]] = None,
4373
4403
  ) -> dict[str, Any]:
4374
4404
  to_object: dict[str, Any] = {}
4405
+ if getv(from_object, ['sdkHttpResponse']) is not None:
4406
+ setv(
4407
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
4408
+ )
4409
+
4375
4410
  if getv(from_object, ['predictions']) is not None:
4376
4411
  setv(
4377
4412
  to_object,
@@ -4539,6 +4574,11 @@ def _CountTokensResponse_from_vertex(
4539
4574
  parent_object: Optional[dict[str, Any]] = None,
4540
4575
  ) -> dict[str, Any]:
4541
4576
  to_object: dict[str, Any] = {}
4577
+ if getv(from_object, ['sdkHttpResponse']) is not None:
4578
+ setv(
4579
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
4580
+ )
4581
+
4542
4582
  if getv(from_object, ['totalTokens']) is not None:
4543
4583
  setv(to_object, ['total_tokens'], getv(from_object, ['totalTokens']))
4544
4584
 
@@ -4550,6 +4590,11 @@ def _ComputeTokensResponse_from_vertex(
4550
4590
  parent_object: Optional[dict[str, Any]] = None,
4551
4591
  ) -> dict[str, Any]:
4552
4592
  to_object: dict[str, Any] = {}
4593
+ if getv(from_object, ['sdkHttpResponse']) is not None:
4594
+ setv(
4595
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
4596
+ )
4597
+
4553
4598
  if getv(from_object, ['tokensInfo']) is not None:
4554
4599
  setv(to_object, ['tokens_info'], getv(from_object, ['tokensInfo']))
4555
4600
 
@@ -4903,7 +4948,9 @@ class Models(_api_module.BaseModule):
4903
4948
  return_value = types.EmbedContentResponse._from_response(
4904
4949
  response=response_dict, kwargs=parameter_model.model_dump()
4905
4950
  )
4906
-
4951
+ return_value.sdk_http_response = types.HttpResponse(
4952
+ headers=response.headers
4953
+ )
4907
4954
  self._api_client._verify_response(return_value)
4908
4955
  return return_value
4909
4956
 
@@ -4979,7 +5026,9 @@ class Models(_api_module.BaseModule):
4979
5026
  return_value = types.GenerateImagesResponse._from_response(
4980
5027
  response=response_dict, kwargs=parameter_model.model_dump()
4981
5028
  )
4982
-
5029
+ return_value.sdk_http_response = types.HttpResponse(
5030
+ headers=response.headers
5031
+ )
4983
5032
  self._api_client._verify_response(return_value)
4984
5033
  return return_value
4985
5034
 
@@ -5081,7 +5130,9 @@ class Models(_api_module.BaseModule):
5081
5130
  return_value = types.EditImageResponse._from_response(
5082
5131
  response=response_dict, kwargs=parameter_model.model_dump()
5083
5132
  )
5084
-
5133
+ return_value.sdk_http_response = types.HttpResponse(
5134
+ headers=response.headers
5135
+ )
5085
5136
  self._api_client._verify_response(return_value)
5086
5137
  return return_value
5087
5138
 
@@ -5150,7 +5201,9 @@ class Models(_api_module.BaseModule):
5150
5201
  return_value = types.UpscaleImageResponse._from_response(
5151
5202
  response=response_dict, kwargs=parameter_model.model_dump()
5152
5203
  )
5153
-
5204
+ return_value.sdk_http_response = types.HttpResponse(
5205
+ headers=response.headers
5206
+ )
5154
5207
  self._api_client._verify_response(return_value)
5155
5208
  return return_value
5156
5209
 
@@ -5494,7 +5547,9 @@ class Models(_api_module.BaseModule):
5494
5547
  return_value = types.CountTokensResponse._from_response(
5495
5548
  response=response_dict, kwargs=parameter_model.model_dump()
5496
5549
  )
5497
-
5550
+ return_value.sdk_http_response = types.HttpResponse(
5551
+ headers=response.headers
5552
+ )
5498
5553
  self._api_client._verify_response(return_value)
5499
5554
  return return_value
5500
5555
 
@@ -5575,7 +5630,9 @@ class Models(_api_module.BaseModule):
5575
5630
  return_value = types.ComputeTokensResponse._from_response(
5576
5631
  response=response_dict, kwargs=parameter_model.model_dump()
5577
5632
  )
5578
-
5633
+ return_value.sdk_http_response = types.HttpResponse(
5634
+ headers=response.headers
5635
+ )
5579
5636
  self._api_client._verify_response(return_value)
5580
5637
  return return_value
5581
5638
 
@@ -6516,7 +6573,9 @@ class AsyncModels(_api_module.BaseModule):
6516
6573
  return_value = types.EmbedContentResponse._from_response(
6517
6574
  response=response_dict, kwargs=parameter_model.model_dump()
6518
6575
  )
6519
-
6576
+ return_value.sdk_http_response = types.HttpResponse(
6577
+ headers=response.headers
6578
+ )
6520
6579
  self._api_client._verify_response(return_value)
6521
6580
  return return_value
6522
6581
 
@@ -6592,7 +6651,9 @@ class AsyncModels(_api_module.BaseModule):
6592
6651
  return_value = types.GenerateImagesResponse._from_response(
6593
6652
  response=response_dict, kwargs=parameter_model.model_dump()
6594
6653
  )
6595
-
6654
+ return_value.sdk_http_response = types.HttpResponse(
6655
+ headers=response.headers
6656
+ )
6596
6657
  self._api_client._verify_response(return_value)
6597
6658
  return return_value
6598
6659
 
@@ -6694,7 +6755,9 @@ class AsyncModels(_api_module.BaseModule):
6694
6755
  return_value = types.EditImageResponse._from_response(
6695
6756
  response=response_dict, kwargs=parameter_model.model_dump()
6696
6757
  )
6697
-
6758
+ return_value.sdk_http_response = types.HttpResponse(
6759
+ headers=response.headers
6760
+ )
6698
6761
  self._api_client._verify_response(return_value)
6699
6762
  return return_value
6700
6763
 
@@ -6763,7 +6826,9 @@ class AsyncModels(_api_module.BaseModule):
6763
6826
  return_value = types.UpscaleImageResponse._from_response(
6764
6827
  response=response_dict, kwargs=parameter_model.model_dump()
6765
6828
  )
6766
-
6829
+ return_value.sdk_http_response = types.HttpResponse(
6830
+ headers=response.headers
6831
+ )
6767
6832
  self._api_client._verify_response(return_value)
6768
6833
  return return_value
6769
6834
 
@@ -7111,7 +7176,9 @@ class AsyncModels(_api_module.BaseModule):
7111
7176
  return_value = types.CountTokensResponse._from_response(
7112
7177
  response=response_dict, kwargs=parameter_model.model_dump()
7113
7178
  )
7114
-
7179
+ return_value.sdk_http_response = types.HttpResponse(
7180
+ headers=response.headers
7181
+ )
7115
7182
  self._api_client._verify_response(return_value)
7116
7183
  return return_value
7117
7184
 
@@ -7191,7 +7258,9 @@ class AsyncModels(_api_module.BaseModule):
7191
7258
  return_value = types.ComputeTokensResponse._from_response(
7192
7259
  response=response_dict, kwargs=parameter_model.model_dump()
7193
7260
  )
7194
-
7261
+ return_value.sdk_http_response = types.HttpResponse(
7262
+ headers=response.headers
7263
+ )
7195
7264
  self._api_client._verify_response(return_value)
7196
7265
  return return_value
7197
7266
 
google/genai/pagers.py CHANGED
@@ -18,7 +18,8 @@
18
18
  # pylint: disable=protected-access
19
19
 
20
20
  import copy
21
- from typing import Any, AsyncIterator,Awaitable, Callable, Generic, Iterator, Literal, TypeVar, Union
21
+ from typing import Any, AsyncIterator, Awaitable, Callable, Generic, Iterator, Literal, TypeVar, Union
22
+ from . import _common
22
23
  from . import types
23
24
 
24
25
  T = TypeVar('T')
@@ -68,7 +69,7 @@ class _BasePager(Generic[T]):
68
69
 
69
70
  @property
70
71
  def page(self) -> list[T]:
71
- """Returns a subset of the entire list of items.
72
+ """Returns a subset of the entire list of items.
72
73
 
73
74
  For the number of items returned, see `pageSize()`.
74
75
 
@@ -115,13 +116,12 @@ class _BasePager(Generic[T]):
115
116
 
116
117
  @property
117
118
  def sdk_http_response(self) -> Union[types.HttpResponse, None]:
118
- """Returns the http response of the API response.
119
- """
119
+ """Returns the http response of the API response."""
120
120
 
121
121
  return self._sdk_http_response
122
122
 
123
123
  @property
124
- def config(self) -> dict[str, Any]:
124
+ def config(self) -> _common.StringDict:
125
125
  """Returns the configuration when making the API request for the next page.
126
126
 
127
127
  A configuration is a set of optional parameters and arguments that can be
google/genai/tokens.py CHANGED
@@ -27,7 +27,7 @@ from . import types
27
27
  logger = logging.getLogger('google_genai.tokens')
28
28
 
29
29
 
30
- def _get_field_masks(setup: Dict[str, Any]) -> str:
30
+ def _get_field_masks(setup: _common.StringDict) -> str:
31
31
  """Return field_masks"""
32
32
  fields = []
33
33
  for k, v in setup.items():
@@ -42,9 +42,9 @@ def _get_field_masks(setup: Dict[str, Any]) -> str:
42
42
 
43
43
 
44
44
  def _convert_bidi_setup_to_token_setup(
45
- request_dict: dict[str, Any],
45
+ request_dict: _common.StringDict,
46
46
  config: Optional[types.CreateAuthTokenConfigOrDict] = None,
47
- ) -> Dict[str, Any]:
47
+ ) -> _common.StringDict:
48
48
  """Converts bidiGenerateContentSetup."""
49
49
  bidi_setup = request_dict.get('bidiGenerateContentSetup')
50
50
  if bidi_setup and bidi_setup.get('setup'):
google/genai/tunings.py CHANGED
@@ -423,6 +423,11 @@ def _TuningJob_from_mldev(
423
423
  parent_object: Optional[dict[str, Any]] = None,
424
424
  ) -> dict[str, Any]:
425
425
  to_object: dict[str, Any] = {}
426
+ if getv(from_object, ['sdkHttpResponse']) is not None:
427
+ setv(
428
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
429
+ )
430
+
426
431
  if getv(from_object, ['name']) is not None:
427
432
  setv(to_object, ['name'], getv(from_object, ['name']))
428
433
 
@@ -532,6 +537,11 @@ def _TuningOperation_from_mldev(
532
537
  parent_object: Optional[dict[str, Any]] = None,
533
538
  ) -> dict[str, Any]:
534
539
  to_object: dict[str, Any] = {}
540
+ if getv(from_object, ['sdkHttpResponse']) is not None:
541
+ setv(
542
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
543
+ )
544
+
535
545
  if getv(from_object, ['name']) is not None:
536
546
  setv(to_object, ['name'], getv(from_object, ['name']))
537
547
 
@@ -596,6 +606,11 @@ def _TuningJob_from_vertex(
596
606
  parent_object: Optional[dict[str, Any]] = None,
597
607
  ) -> dict[str, Any]:
598
608
  to_object: dict[str, Any] = {}
609
+ if getv(from_object, ['sdkHttpResponse']) is not None:
610
+ setv(
611
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
612
+ )
613
+
599
614
  if getv(from_object, ['name']) is not None:
600
615
  setv(to_object, ['name'], getv(from_object, ['name']))
601
616
 
@@ -784,7 +799,9 @@ class Tunings(_api_module.BaseModule):
784
799
  return_value = types.TuningJob._from_response(
785
800
  response=response_dict, kwargs=parameter_model.model_dump()
786
801
  )
787
-
802
+ return_value.sdk_http_response = types.HttpResponse(
803
+ headers=response.headers
804
+ )
788
805
  self._api_client._verify_response(return_value)
789
806
  return return_value
790
807
 
@@ -918,7 +935,9 @@ class Tunings(_api_module.BaseModule):
918
935
  return_value = types.TuningJob._from_response(
919
936
  response=response_dict, kwargs=parameter_model.model_dump()
920
937
  )
921
-
938
+ return_value.sdk_http_response = types.HttpResponse(
939
+ headers=response.headers
940
+ )
922
941
  self._api_client._verify_response(return_value)
923
942
  return return_value
924
943
 
@@ -987,7 +1006,9 @@ class Tunings(_api_module.BaseModule):
987
1006
  return_value = types.TuningOperation._from_response(
988
1007
  response=response_dict, kwargs=parameter_model.model_dump()
989
1008
  )
990
-
1009
+ return_value.sdk_http_response = types.HttpResponse(
1010
+ headers=response.headers
1011
+ )
991
1012
  self._api_client._verify_response(return_value)
992
1013
  return return_value
993
1014
 
@@ -1128,7 +1149,9 @@ class AsyncTunings(_api_module.BaseModule):
1128
1149
  return_value = types.TuningJob._from_response(
1129
1150
  response=response_dict, kwargs=parameter_model.model_dump()
1130
1151
  )
1131
-
1152
+ return_value.sdk_http_response = types.HttpResponse(
1153
+ headers=response.headers
1154
+ )
1132
1155
  self._api_client._verify_response(return_value)
1133
1156
  return return_value
1134
1157
 
@@ -1264,7 +1287,9 @@ class AsyncTunings(_api_module.BaseModule):
1264
1287
  return_value = types.TuningJob._from_response(
1265
1288
  response=response_dict, kwargs=parameter_model.model_dump()
1266
1289
  )
1267
-
1290
+ return_value.sdk_http_response = types.HttpResponse(
1291
+ headers=response.headers
1292
+ )
1268
1293
  self._api_client._verify_response(return_value)
1269
1294
  return return_value
1270
1295
 
@@ -1333,7 +1358,9 @@ class AsyncTunings(_api_module.BaseModule):
1333
1358
  return_value = types.TuningOperation._from_response(
1334
1359
  response=response_dict, kwargs=parameter_model.model_dump()
1335
1360
  )
1336
-
1361
+ return_value.sdk_http_response = types.HttpResponse(
1362
+ headers=response.headers
1363
+ )
1337
1364
  self._api_client._verify_response(return_value)
1338
1365
  return return_value
1339
1366
 
google/genai/types.py CHANGED
@@ -5606,6 +5606,9 @@ EmbedContentMetadataOrDict = Union[
5606
5606
  class EmbedContentResponse(_common.BaseModel):
5607
5607
  """Response for the embed_content method."""
5608
5608
 
5609
+ sdk_http_response: Optional[HttpResponse] = Field(
5610
+ default=None, description="""Used to retain the full HTTP response."""
5611
+ )
5609
5612
  embeddings: Optional[list[ContentEmbedding]] = Field(
5610
5613
  default=None,
5611
5614
  description="""The embeddings for each request, in the same order as provided in
@@ -5622,6 +5625,9 @@ class EmbedContentResponse(_common.BaseModel):
5622
5625
  class EmbedContentResponseDict(TypedDict, total=False):
5623
5626
  """Response for the embed_content method."""
5624
5627
 
5628
+ sdk_http_response: Optional[HttpResponseDict]
5629
+ """Used to retain the full HTTP response."""
5630
+
5625
5631
  embeddings: Optional[list[ContentEmbeddingDict]]
5626
5632
  """The embeddings for each request, in the same order as provided in
5627
5633
  the batch request.
@@ -6111,6 +6117,9 @@ GeneratedImageOrDict = Union[GeneratedImage, GeneratedImageDict]
6111
6117
  class GenerateImagesResponse(_common.BaseModel):
6112
6118
  """The output images response."""
6113
6119
 
6120
+ sdk_http_response: Optional[HttpResponse] = Field(
6121
+ default=None, description="""Used to retain the full HTTP response."""
6122
+ )
6114
6123
  generated_images: Optional[list[GeneratedImage]] = Field(
6115
6124
  default=None,
6116
6125
  description="""List of generated images.
@@ -6123,10 +6132,24 @@ class GenerateImagesResponse(_common.BaseModel):
6123
6132
  """,
6124
6133
  )
6125
6134
 
6135
+ @property
6136
+ def images(self) -> list[Optional[Image]]:
6137
+ """Returns the list of all generated images.
6138
+
6139
+ A convenience method for accessing the images. Some attributes of the
6140
+ generated image are only available through the ``GeneratedImage`` object.
6141
+ """
6142
+ if not self.generated_images:
6143
+ return []
6144
+ return [generated_image.image for generated_image in self.generated_images]
6145
+
6126
6146
 
6127
6147
  class GenerateImagesResponseDict(TypedDict, total=False):
6128
6148
  """The output images response."""
6129
6149
 
6150
+ sdk_http_response: Optional[HttpResponseDict]
6151
+ """Used to retain the full HTTP response."""
6152
+
6130
6153
  generated_images: Optional[list[GeneratedImageDict]]
6131
6154
  """List of generated images.
6132
6155
  """
@@ -6537,6 +6560,9 @@ _EditImageParametersOrDict = Union[
6537
6560
  class EditImageResponse(_common.BaseModel):
6538
6561
  """Response for the request to edit an image."""
6539
6562
 
6563
+ sdk_http_response: Optional[HttpResponse] = Field(
6564
+ default=None, description="""Used to retain the full HTTP response."""
6565
+ )
6540
6566
  generated_images: Optional[list[GeneratedImage]] = Field(
6541
6567
  default=None, description="""Generated images."""
6542
6568
  )
@@ -6545,6 +6571,9 @@ class EditImageResponse(_common.BaseModel):
6545
6571
  class EditImageResponseDict(TypedDict, total=False):
6546
6572
  """Response for the request to edit an image."""
6547
6573
 
6574
+ sdk_http_response: Optional[HttpResponseDict]
6575
+ """Used to retain the full HTTP response."""
6576
+
6548
6577
  generated_images: Optional[list[GeneratedImageDict]]
6549
6578
  """Generated images."""
6550
6579
 
@@ -6678,6 +6707,9 @@ _UpscaleImageAPIParametersOrDict = Union[
6678
6707
 
6679
6708
  class UpscaleImageResponse(_common.BaseModel):
6680
6709
 
6710
+ sdk_http_response: Optional[HttpResponse] = Field(
6711
+ default=None, description="""Used to retain the full HTTP response."""
6712
+ )
6681
6713
  generated_images: Optional[list[GeneratedImage]] = Field(
6682
6714
  default=None, description="""Generated images."""
6683
6715
  )
@@ -6685,6 +6717,9 @@ class UpscaleImageResponse(_common.BaseModel):
6685
6717
 
6686
6718
  class UpscaleImageResponseDict(TypedDict, total=False):
6687
6719
 
6720
+ sdk_http_response: Optional[HttpResponseDict]
6721
+ """Used to retain the full HTTP response."""
6722
+
6688
6723
  generated_images: Optional[list[GeneratedImageDict]]
6689
6724
  """Generated images."""
6690
6725
 
@@ -7383,6 +7418,9 @@ _CountTokensParametersOrDict = Union[
7383
7418
  class CountTokensResponse(_common.BaseModel):
7384
7419
  """Response for counting tokens."""
7385
7420
 
7421
+ sdk_http_response: Optional[HttpResponse] = Field(
7422
+ default=None, description="""Used to retain the full HTTP response."""
7423
+ )
7386
7424
  total_tokens: Optional[int] = Field(
7387
7425
  default=None, description="""Total number of tokens."""
7388
7426
  )
@@ -7395,6 +7433,9 @@ class CountTokensResponse(_common.BaseModel):
7395
7433
  class CountTokensResponseDict(TypedDict, total=False):
7396
7434
  """Response for counting tokens."""
7397
7435
 
7436
+ sdk_http_response: Optional[HttpResponseDict]
7437
+ """Used to retain the full HTTP response."""
7438
+
7398
7439
  total_tokens: Optional[int]
7399
7440
  """Total number of tokens."""
7400
7441
 
@@ -7495,6 +7536,9 @@ TokensInfoOrDict = Union[TokensInfo, TokensInfoDict]
7495
7536
  class ComputeTokensResponse(_common.BaseModel):
7496
7537
  """Response for computing tokens."""
7497
7538
 
7539
+ sdk_http_response: Optional[HttpResponse] = Field(
7540
+ default=None, description="""Used to retain the full HTTP response."""
7541
+ )
7498
7542
  tokens_info: Optional[list[TokensInfo]] = Field(
7499
7543
  default=None,
7500
7544
  description="""Lists of tokens info from the input. A ComputeTokensRequest could have multiple instances with a prompt in each instance. We also need to return lists of tokens info for the request with multiple instances.""",
@@ -7504,6 +7548,9 @@ class ComputeTokensResponse(_common.BaseModel):
7504
7548
  class ComputeTokensResponseDict(TypedDict, total=False):
7505
7549
  """Response for computing tokens."""
7506
7550
 
7551
+ sdk_http_response: Optional[HttpResponseDict]
7552
+ """Used to retain the full HTTP response."""
7553
+
7507
7554
  tokens_info: Optional[list[TokensInfoDict]]
7508
7555
  """Lists of tokens info from the input. A ComputeTokensRequest could have multiple instances with a prompt in each instance. We also need to return lists of tokens info for the request with multiple instances."""
7509
7556
 
@@ -8775,6 +8822,9 @@ DistillationSpecOrDict = Union[DistillationSpec, DistillationSpecDict]
8775
8822
  class TuningJob(_common.BaseModel):
8776
8823
  """A tuning job."""
8777
8824
 
8825
+ sdk_http_response: Optional[HttpResponse] = Field(
8826
+ default=None, description="""Used to retain the full HTTP response."""
8827
+ )
8778
8828
  name: Optional[str] = Field(
8779
8829
  default=None,
8780
8830
  description="""Output only. Identifier. Resource name of a TuningJob. Format: `projects/{project}/locations/{location}/tuningJobs/{tuning_job}`""",
@@ -8874,6 +8924,9 @@ class TuningJob(_common.BaseModel):
8874
8924
  class TuningJobDict(TypedDict, total=False):
8875
8925
  """A tuning job."""
8876
8926
 
8927
+ sdk_http_response: Optional[HttpResponseDict]
8928
+ """Used to retain the full HTTP response."""
8929
+
8877
8930
  name: Optional[str]
8878
8931
  """Output only. Identifier. Resource name of a TuningJob. Format: `projects/{project}/locations/{location}/tuningJobs/{tuning_job}`"""
8879
8932
 
@@ -9228,6 +9281,9 @@ _CreateTuningJobParametersOrDict = Union[
9228
9281
  class TuningOperation(_common.BaseModel):
9229
9282
  """A long-running operation."""
9230
9283
 
9284
+ sdk_http_response: Optional[HttpResponse] = Field(
9285
+ default=None, description="""Used to retain the full HTTP response."""
9286
+ )
9231
9287
  name: Optional[str] = Field(
9232
9288
  default=None,
9233
9289
  description="""The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`.""",
@@ -9249,6 +9305,9 @@ class TuningOperation(_common.BaseModel):
9249
9305
  class TuningOperationDict(TypedDict, total=False):
9250
9306
  """A long-running operation."""
9251
9307
 
9308
+ sdk_http_response: Optional[HttpResponseDict]
9309
+ """Used to retain the full HTTP response."""
9310
+
9252
9311
  name: Optional[str]
9253
9312
  """The server-assigned name, which is only unique within the same service that originally returns it. If you use the default HTTP mapping, the `name` should be a resource name ending with `operations/{unique_id}`."""
9254
9313
 
google/genai/version.py CHANGED
@@ -13,4 +13,4 @@
13
13
  # limitations under the License.
14
14
  #
15
15
 
16
- __version__ = '1.27.0' # x-release-please-version
16
+ __version__ = '1.28.0' # x-release-please-version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: google-genai
3
- Version: 1.27.0
3
+ Version: 1.28.0
4
4
  Summary: GenAI Python SDK
5
5
  Author-email: Google LLC <googleapis-packages@google.com>
6
6
  License: Apache-2.0
@@ -0,0 +1,35 @@
1
+ google/genai/__init__.py,sha256=SKz_9WQKA3R4OpJIDJlgssVfizLNDG2tuWtOD9pxrPE,729
2
+ google/genai/_adapters.py,sha256=Kok38miNYJff2n--l0zEK_hbq0y2rWOH7k75J7SMYbQ,1744
3
+ google/genai/_api_client.py,sha256=xleLwNglnLnRUVOZeKrdSyBjcZNIqjx2DX9djz904gk,57552
4
+ google/genai/_api_module.py,sha256=lj8eUWx8_LBGBz-49qz6_ywWm3GYp3d8Bg5JoOHbtbI,902
5
+ google/genai/_automatic_function_calling_util.py,sha256=IJkPq2fT9pYxYm5Pbu5-e0nBoZKoZla7yT4_txWRKLs,10324
6
+ google/genai/_base_url.py,sha256=E5H4dew14Y16qfnB3XRnjSCi19cJVlkaMNoM_8ip-PM,1597
7
+ google/genai/_common.py,sha256=SmBlz7AQZbKbT8KE5vsvK5Iz1OaRwHF6J51KDJBbjMo,19936
8
+ google/genai/_extra_utils.py,sha256=6mxUnbwKkrAJ9zR8JP4nCKuA0F1BFqAc2t5mzdAONxk,20603
9
+ google/genai/_live_converters.py,sha256=pIcEfsAxjV1zeWmxMNigDD7ETHiuutp-a2y0HQThdmU,100162
10
+ google/genai/_mcp_utils.py,sha256=HuWJ8FUjquv40Mf_QjcL5r5yXWrS-JjINsjlOSbbyAc,3870
11
+ google/genai/_replay_api_client.py,sha256=MRUxUWCC9PoTk-NxsK3rGB8yw8cCrUa8ZeTVU3oEguw,21729
12
+ google/genai/_test_api_client.py,sha256=4ruFIy5_1qcbKqqIBu3HSQbpSOBrxiecBtDZaTGFR1s,4797
13
+ google/genai/_tokens_converters.py,sha256=ClWTsgcqn91zSw_qTqLPTNSP1-_G8s-NlBCD8-DQniw,23803
14
+ google/genai/_transformers.py,sha256=l7Rf4OvaDG_91jTrdCeHLBAm1J7_pyYwJW1oQM6Q9MI,37431
15
+ google/genai/batches.py,sha256=a8X0wi8D6d7WC8873C2oVtk_NBYbd8xeI77GSkww4Nc,81094
16
+ google/genai/caches.py,sha256=isEzVYJgQVOjHf0XkFl86HOXzoYFXB-PgEVqwuo1V4s,64673
17
+ google/genai/chats.py,sha256=0QdOUeWEYDQgAWBy1f7a3z3yY9S8tXSowUzNrzazzj4,16651
18
+ google/genai/client.py,sha256=wXnfZBSv9p-yKtX_gabUrfBXoYHuqHhzK_VgwRttMgY,10777
19
+ google/genai/errors.py,sha256=Cd3M1la1VgvRh0vLgOzL9x8fgXnw96A6tj-kfsS0wi8,5586
20
+ google/genai/files.py,sha256=Z9CP2RLAZlZDE3zWXVNA2LF3x7wJTXOhNzDoSyHmr9k,40154
21
+ google/genai/live.py,sha256=R7cAtesP5-Yp685H00EpgmzNsMNjERIR8L-m5e5kEMI,39469
22
+ google/genai/live_music.py,sha256=3GG9nsto8Vhkohcs-4CPMS4DFp1ZtMuLYzHfvEPYAeg,6971
23
+ google/genai/models.py,sha256=ci7dOuCGm8ky4m-rD7-_Ur9hzGUKWBofmlKZIA_BwLQ,242026
24
+ google/genai/operations.py,sha256=3eudPaItN6_JJKMWNT9lLIJLUGyAQfFK1xken7Rv8vQ,12814
25
+ google/genai/pagers.py,sha256=m0SfWWn1EJs2k1On3DZx371qb8g2BRm_188ExsicIRc,7098
26
+ google/genai/py.typed,sha256=RsMFoLwBkAvY05t6izop4UHZtqOPLiKp3GkIEizzmQY,40
27
+ google/genai/tokens.py,sha256=PvAIGl93bLCtc3bxaBS1-NE4et_xn4XBZ1bJn9ZYxP8,12502
28
+ google/genai/tunings.py,sha256=ctSApLv-Lpjrkm2-JE8fQo332706EMXp9b9u552wNTE,49996
29
+ google/genai/types.py,sha256=rIiMTLQQiRz7frgL3uchuXUCQciJEIMBV-B_1okILck,476572
30
+ google/genai/version.py,sha256=YPf09ydfdYGYELmthoUhjWan0Yv6J2Cz6saNEHhqN-c,627
31
+ google_genai-1.28.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
32
+ google_genai-1.28.0.dist-info/METADATA,sha256=_G5eO1nP7bswlUTGcuh46FEbSF_vLZ7Ir6G76ANNISk,43091
33
+ google_genai-1.28.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
+ google_genai-1.28.0.dist-info/top_level.txt,sha256=_1QvSJIhFAGfxb79D6DhB7SUw2X6T4rwnz_LLrbcD3c,7
35
+ google_genai-1.28.0.dist-info/RECORD,,
@@ -1,35 +0,0 @@
1
- google/genai/__init__.py,sha256=SYTxz3Ho06pP2TBlvDU0FkUJz8ytbR3MgEpS9HvVYq4,709
2
- google/genai/_adapters.py,sha256=Kok38miNYJff2n--l0zEK_hbq0y2rWOH7k75J7SMYbQ,1744
3
- google/genai/_api_client.py,sha256=X9JVR_XBnedZgkOKbBcvJjMuHupA75XXJkmlrVZqTw0,53102
4
- google/genai/_api_module.py,sha256=lj8eUWx8_LBGBz-49qz6_ywWm3GYp3d8Bg5JoOHbtbI,902
5
- google/genai/_automatic_function_calling_util.py,sha256=IJkPq2fT9pYxYm5Pbu5-e0nBoZKoZla7yT4_txWRKLs,10324
6
- google/genai/_base_url.py,sha256=E5H4dew14Y16qfnB3XRnjSCi19cJVlkaMNoM_8ip-PM,1597
7
- google/genai/_common.py,sha256=sJpzeoEJ6dZSPPfHb2Dsar-F5KmpwLjFqNSkxxxVfS8,19876
8
- google/genai/_extra_utils.py,sha256=jWhJIdaFoVsrvExl6L7of3Bu8miSKvVidx4pbQ6EO2A,20571
9
- google/genai/_live_converters.py,sha256=pIcEfsAxjV1zeWmxMNigDD7ETHiuutp-a2y0HQThdmU,100162
10
- google/genai/_mcp_utils.py,sha256=khECx-DMuHemKzOQQ3msWp7FivPeEOnl3n1lvWc_b5o,3833
11
- google/genai/_replay_api_client.py,sha256=2ndavmUMySvjLIdYEvjPZIOPfc-IA5rbWQgEwWuWpfc,21567
12
- google/genai/_test_api_client.py,sha256=4ruFIy5_1qcbKqqIBu3HSQbpSOBrxiecBtDZaTGFR1s,4797
13
- google/genai/_tokens_converters.py,sha256=ClWTsgcqn91zSw_qTqLPTNSP1-_G8s-NlBCD8-DQniw,23803
14
- google/genai/_transformers.py,sha256=uTRSd9qrUZbJoFzLEWy3wGR_j1KqVg5cypGzQM1Mc4w,37357
15
- google/genai/batches.py,sha256=a8X0wi8D6d7WC8873C2oVtk_NBYbd8xeI77GSkww4Nc,81094
16
- google/genai/caches.py,sha256=isEzVYJgQVOjHf0XkFl86HOXzoYFXB-PgEVqwuo1V4s,64673
17
- google/genai/chats.py,sha256=0QdOUeWEYDQgAWBy1f7a3z3yY9S8tXSowUzNrzazzj4,16651
18
- google/genai/client.py,sha256=wXnfZBSv9p-yKtX_gabUrfBXoYHuqHhzK_VgwRttMgY,10777
19
- google/genai/errors.py,sha256=IdSymOuUJDprfPRBhBtFDkc_XX81UvgNbWrOLR8L2GU,5582
20
- google/genai/files.py,sha256=Z9CP2RLAZlZDE3zWXVNA2LF3x7wJTXOhNzDoSyHmr9k,40154
21
- google/genai/live.py,sha256=WvOPBFDwD2eyUx89XCW6oudKtlK7960RqQuk5-SY1Ac,39482
22
- google/genai/live_music.py,sha256=3GG9nsto8Vhkohcs-4CPMS4DFp1ZtMuLYzHfvEPYAeg,6971
23
- google/genai/models.py,sha256=wdxOAA2OTklPBobfvKSDLqdihd74IIG6lco-7Z2S4xg,239491
24
- google/genai/operations.py,sha256=3eudPaItN6_JJKMWNT9lLIJLUGyAQfFK1xken7Rv8vQ,12814
25
- google/genai/pagers.py,sha256=hlfLtH8Fv_eU19bfqKaabvWqDZYhIYXhOVuoH2oBJkA,7077
26
- google/genai/py.typed,sha256=RsMFoLwBkAvY05t6izop4UHZtqOPLiKp3GkIEizzmQY,40
27
- google/genai/tokens.py,sha256=QGW1jI0Y5wXqiaad0-N6Utgh9sK4TK0todHf5h0GLeI,12490
28
- google/genai/tunings.py,sha256=diQSMojun63gFI9b-bluxTYjwbOwEIjviMJwHvUb9A4,48961
29
- google/genai/types.py,sha256=0otLX5sfNZoW98bgHI7D2NAYTnF5MKXwvRuKHEqQhv0,474334
30
- google/genai/version.py,sha256=zQZWqve_yrf9cPtiYvuJgv4hhwEymigHvKuPVVKoisc,627
31
- google_genai-1.27.0.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
32
- google_genai-1.27.0.dist-info/METADATA,sha256=3h-l2dUas9jaOIvWv6r6Vnd1gWz-Ppz6Hn7i4sHkOcM,43091
33
- google_genai-1.27.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
34
- google_genai-1.27.0.dist-info/top_level.txt,sha256=_1QvSJIhFAGfxb79D6DhB7SUw2X6T4rwnz_LLrbcD3c,7
35
- google_genai-1.27.0.dist-info/RECORD,,