google-genai 1.28.0__py3-none-any.whl → 1.30.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.
@@ -20,23 +20,21 @@ The BaseApiClient is intended to be a private module and is subject to change.
20
20
  """
21
21
 
22
22
  import asyncio
23
- from collections.abc import Awaitable, Generator
23
+ from collections.abc import Generator
24
24
  import copy
25
25
  from dataclasses import dataclass
26
- import datetime
27
- import http
28
26
  import inspect
29
27
  import io
30
28
  import json
31
29
  import logging
32
30
  import math
33
31
  import os
34
- import ssl
35
32
  import random
33
+ import ssl
36
34
  import sys
37
35
  import threading
38
36
  import time
39
- from typing import Any, AsyncIterator, Optional, TYPE_CHECKING, Tuple, Union
37
+ from typing import Any, AsyncIterator, Iterator, Optional, Tuple, TYPE_CHECKING, Union
40
38
  from urllib.parse import urlparse
41
39
  from urllib.parse import urlunparse
42
40
 
@@ -48,7 +46,6 @@ from google.auth.credentials import Credentials
48
46
  from google.auth.transport.requests import Request
49
47
  import httpx
50
48
  from pydantic import BaseModel
51
- from pydantic import Field
52
49
  from pydantic import ValidationError
53
50
  import tenacity
54
51
 
@@ -56,11 +53,11 @@ from . import _common
56
53
  from . import errors
57
54
  from . import version
58
55
  from .types import HttpOptions
59
- from .types import HttpOptionsDict
60
56
  from .types import HttpOptionsOrDict
61
57
  from .types import HttpResponse as SdkHttpResponse
62
58
  from .types import HttpRetryOptions
63
59
 
60
+
64
61
  try:
65
62
  from websockets.asyncio.client import connect as ws_connect
66
63
  except ModuleNotFoundError:
@@ -238,12 +235,12 @@ class HttpResponse:
238
235
  self.headers = headers
239
236
  elif isinstance(headers, httpx.Headers):
240
237
  self.headers = {
241
- key: ', '.join(headers.get_list(key))
242
- for key in headers.keys()}
238
+ key: ', '.join(headers.get_list(key)) for key in headers.keys()
239
+ }
243
240
  elif type(headers).__name__ == 'CIMultiDictProxy':
244
241
  self.headers = {
245
- key: ', '.join(headers.getall(key))
246
- for key in headers.keys()}
242
+ key: ', '.join(headers.getall(key)) for key in headers.keys()
243
+ }
247
244
 
248
245
  self.status_code: int = 200
249
246
  self.response_stream = response_stream
@@ -265,68 +262,32 @@ class HttpResponse:
265
262
  def json(self) -> Any:
266
263
  if not self.response_stream[0]: # Empty response
267
264
  return ''
268
- return json.loads(self.response_stream[0])
265
+ return self._load_json_from_response(self.response_stream[0])
269
266
 
270
267
  def segments(self) -> Generator[Any, None, None]:
271
268
  if isinstance(self.response_stream, list):
272
269
  # list of objects retrieved from replay or from non-streaming API.
273
270
  for chunk in self.response_stream:
274
- yield json.loads(chunk) if chunk else {}
271
+ yield self._load_json_from_response(chunk) if chunk else {}
275
272
  elif self.response_stream is None:
276
273
  yield from []
277
274
  else:
278
275
  # Iterator of objects retrieved from the API.
279
- for chunk in self.response_stream.iter_lines(): # type: ignore[union-attr]
280
- if chunk:
281
- # In streaming mode, the chunk of JSON is prefixed with "data:" which
282
- # we must strip before parsing.
283
- if not isinstance(chunk, str):
284
- chunk = chunk.decode('utf-8')
285
- if chunk.startswith('data: '):
286
- chunk = chunk[len('data: ') :]
287
- yield json.loads(chunk)
276
+ for chunk in self._iter_response_stream():
277
+ yield self._load_json_from_response(chunk)
288
278
 
289
279
  async def async_segments(self) -> AsyncIterator[Any]:
290
280
  if isinstance(self.response_stream, list):
291
281
  # list of objects retrieved from replay or from non-streaming API.
292
282
  for chunk in self.response_stream:
293
- yield json.loads(chunk) if chunk else {}
283
+ yield self._load_json_from_response(chunk) if chunk else {}
294
284
  elif self.response_stream is None:
295
285
  async for c in []: # type: ignore[attr-defined]
296
286
  yield c
297
287
  else:
298
288
  # Iterator of objects retrieved from the API.
299
- if hasattr(self.response_stream, 'aiter_lines'):
300
- async for chunk in self.response_stream.aiter_lines():
301
- # This is httpx.Response.
302
- if chunk:
303
- # In async streaming mode, the chunk of JSON is prefixed with
304
- # "data:" which we must strip before parsing.
305
- if not isinstance(chunk, str):
306
- chunk = chunk.decode('utf-8')
307
- if chunk.startswith('data: '):
308
- chunk = chunk[len('data: ') :]
309
- yield json.loads(chunk)
310
- elif hasattr(self.response_stream, 'content'):
311
- # This is aiohttp.ClientResponse.
312
- try:
313
- while True:
314
- chunk = await self.response_stream.content.readline()
315
- if not chunk:
316
- break
317
- # In async streaming mode, the chunk of JSON is prefixed with
318
- # "data:" which we must strip before parsing.
319
- chunk = chunk.decode('utf-8')
320
- if chunk.startswith('data: '):
321
- chunk = chunk[len('data: ') :]
322
- chunk = chunk.strip()
323
- if chunk:
324
- yield json.loads(chunk)
325
- finally:
326
- if hasattr(self, '_session') and self._session:
327
- await self._session.close()
328
- else:
329
- raise ValueError('Error parsing streaming response.')
289
+ async for chunk in self._aiter_response_stream():
290
+ yield self._load_json_from_response(chunk)
330
291
 
331
292
  def byte_segments(self) -> Generator[Union[bytes, Any], None, None]:
332
293
  if isinstance(self.byte_stream, list):
@@ -345,6 +306,134 @@ class HttpResponse:
345
306
  for attribute in dir(self):
346
307
  response_payload[attribute] = copy.deepcopy(getattr(self, attribute))
347
308
 
309
+ def _iter_response_stream(self) -> Iterator[str]:
310
+ """Iterates over chunks retrieved from the API."""
311
+ if not isinstance(self.response_stream, httpx.Response):
312
+ raise TypeError(
313
+ 'Expected self.response_stream to be an httpx.Response object, '
314
+ f'but got {type(self.response_stream).__name__}.'
315
+ )
316
+
317
+ chunk = ''
318
+ balance = 0
319
+ for line in self.response_stream.iter_lines():
320
+ if not line:
321
+ continue
322
+
323
+ # In streaming mode, the response of JSON is prefixed with "data: " which
324
+ # we must strip before parsing.
325
+ if line.startswith('data: '):
326
+ yield line[len('data: '):]
327
+ continue
328
+
329
+ # When API returns an error message, it comes line by line. So we buffer
330
+ # the lines until a complete JSON string is read. A complete JSON string
331
+ # is found when the balance is 0.
332
+ for c in line:
333
+ if c == '{':
334
+ balance += 1
335
+ elif c == '}':
336
+ balance -= 1
337
+
338
+ chunk += line
339
+ if balance == 0:
340
+ yield chunk
341
+ chunk = ''
342
+
343
+ # If there is any remaining chunk, yield it.
344
+ if chunk:
345
+ yield chunk
346
+
347
+ async def _aiter_response_stream(self) -> AsyncIterator[str]:
348
+ """Asynchronously iterates over chunks retrieved from the API."""
349
+ is_valid_response = isinstance(self.response_stream, httpx.Response) or (
350
+ has_aiohttp and isinstance(self.response_stream, aiohttp.ClientResponse)
351
+ )
352
+ if not is_valid_response:
353
+ raise TypeError(
354
+ 'Expected self.response_stream to be an httpx.Response or'
355
+ ' aiohttp.ClientResponse object, but got'
356
+ f' {type(self.response_stream).__name__}.'
357
+ )
358
+
359
+ chunk = ''
360
+ balance = 0
361
+ # httpx.Response has a dedicated async line iterator.
362
+ if isinstance(self.response_stream, httpx.Response):
363
+ async for line in self.response_stream.aiter_lines():
364
+ if not line:
365
+ continue
366
+ # In streaming mode, the response of JSON is prefixed with "data: "
367
+ # which we must strip before parsing.
368
+ if line.startswith('data: '):
369
+ yield line[len('data: '):]
370
+ continue
371
+
372
+ # When API returns an error message, it comes line by line. So we buffer
373
+ # the lines until a complete JSON string is read. A complete JSON string
374
+ # is found when the balance is 0.
375
+ for c in line:
376
+ if c == '{':
377
+ balance += 1
378
+ elif c == '}':
379
+ balance -= 1
380
+
381
+ chunk += line
382
+ if balance == 0:
383
+ yield chunk
384
+ chunk = ''
385
+
386
+ # aiohttp.ClientResponse uses a content stream that we read line by line.
387
+ elif has_aiohttp and isinstance(
388
+ self.response_stream, aiohttp.ClientResponse
389
+ ):
390
+ while True:
391
+ # Read a line from the stream. This returns bytes.
392
+ line_bytes = await self.response_stream.content.readline()
393
+ if not line_bytes:
394
+ break
395
+ # Decode the bytes and remove trailing whitespace and newlines.
396
+ line = line_bytes.decode('utf-8').rstrip()
397
+ if not line:
398
+ continue
399
+
400
+ # In streaming mode, the response of JSON is prefixed with "data: "
401
+ # which we must strip before parsing.
402
+ if line.startswith('data: '):
403
+ yield line[len('data: '):]
404
+ continue
405
+
406
+ # When API returns an error message, it comes line by line. So we buffer
407
+ # the lines until a complete JSON string is read. A complete JSON string
408
+ # is found when the balance is 0.
409
+ for c in line:
410
+ if c == '{':
411
+ balance += 1
412
+ elif c == '}':
413
+ balance -= 1
414
+
415
+ chunk += line
416
+ if balance == 0:
417
+ yield chunk
418
+ chunk = ''
419
+
420
+ # If there is any remaining chunk, yield it.
421
+ if chunk:
422
+ yield chunk
423
+
424
+ if hasattr(self, '_session') and self._session:
425
+ await self._session.close()
426
+
427
+ @classmethod
428
+ def _load_json_from_response(cls, response: Any) -> Any:
429
+ """Loads JSON from the response, or raises an error if the parsing fails."""
430
+ try:
431
+ return json.loads(response)
432
+ except json.JSONDecodeError as e:
433
+ raise errors.UnknownApiResponseError(
434
+ f'Failed to parse response as JSON. Raw response: {response}'
435
+ ) from e
436
+
348
437
 
349
438
  # Default retry options.
350
439
  # The config is based on https://cloud.google.com/storage/docs/retry-strategy.
@@ -548,7 +637,7 @@ class BaseApiClient:
548
637
 
549
638
  has_sufficient_auth = (self.project and self.location) or self.api_key
550
639
 
551
- if (not has_sufficient_auth and not validated_http_options.base_url):
640
+ if not has_sufficient_auth and not validated_http_options.base_url:
552
641
  # Skip sufficient auth check if base url is provided in http options.
553
642
  raise ValueError(
554
643
  'Project and location or API key must be set when using the Vertex '
@@ -41,6 +41,39 @@ _py_builtin_type_to_schema_type = {
41
41
  }
42
42
 
43
43
 
44
+ def _raise_for_unsupported_param(
45
+ param: inspect.Parameter, func_name: str, exception: Union[Exception, type[Exception]]
46
+ ) -> None:
47
+ raise ValueError(
48
+ f'Failed to parse the parameter {param} of function {func_name} for'
49
+ ' automatic function calling.Automatic function calling works best with'
50
+ ' simpler function signature schema, consider manually parsing your'
51
+ f' function declaration for function {func_name}.'
52
+ ) from exception
53
+
54
+
55
+ def _handle_params_as_deferred_annotations(param: inspect.Parameter, annotation_under_future: dict[str, Any], name: str) -> inspect.Parameter:
56
+ """Catches the case when type hints are stored as strings."""
57
+ if isinstance(param.annotation, str):
58
+ param = param.replace(annotation=annotation_under_future[name])
59
+ return param
60
+
61
+
62
+ def _add_unevaluated_items_to_fixed_len_tuple_schema(
63
+ json_schema: dict[str, Any]
64
+ ) -> dict[str, Any]:
65
+ if (
66
+ json_schema.get('maxItems')
67
+ and (
68
+ json_schema.get('prefixItems')
69
+ and len(json_schema['prefixItems']) == json_schema['maxItems']
70
+ )
71
+ and json_schema.get('type') == 'array'
72
+ ):
73
+ json_schema['unevaluatedItems'] = False
74
+ return json_schema
75
+
76
+
44
77
  def _is_builtin_primitive_or_compound(
45
78
  annotation: inspect.Parameter.annotation, # type: ignore[valid-type]
46
79
  ) -> bool:
@@ -92,7 +125,7 @@ def _is_default_value_compatible(
92
125
  return False
93
126
 
94
127
 
95
- def _parse_schema_from_parameter(
128
+ def _parse_schema_from_parameter( # type: ignore[return]
96
129
  api_option: Literal['VERTEX_AI', 'GEMINI_API'],
97
130
  param: inspect.Parameter,
98
131
  func_name: str,
@@ -267,12 +300,7 @@ def _parse_schema_from_parameter(
267
300
  )
268
301
  schema.required = _get_required_fields(schema)
269
302
  return schema
270
- raise ValueError(
271
- f'Failed to parse the parameter {param} of function {func_name} for'
272
- ' automatic function calling.Automatic function calling works best with'
273
- ' simpler function signature schema, consider manually parsing your'
274
- f' function declaration for function {func_name}.'
275
- )
303
+ _raise_for_unsupported_param(param, func_name, ValueError)
276
304
 
277
305
 
278
306
  def _get_required_fields(schema: types.Schema) -> Optional[list[str]]:
@@ -312,6 +312,11 @@ def _GoogleSearch_to_mldev(
312
312
  _Interval_to_mldev(getv(from_object, ['time_range_filter']), to_object),
313
313
  )
314
314
 
315
+ if getv(from_object, ['exclude_domains']) is not None:
316
+ raise ValueError(
317
+ 'exclude_domains parameter is not supported in Gemini API.'
318
+ )
319
+
315
320
  return to_object
316
321
 
317
322
 
@@ -359,6 +364,17 @@ def _UrlContext_to_mldev(
359
364
  return to_object
360
365
 
361
366
 
367
+ def _ToolComputerUse_to_mldev(
368
+ from_object: Union[dict[str, Any], object],
369
+ parent_object: Optional[dict[str, Any]] = None,
370
+ ) -> dict[str, Any]:
371
+ to_object: dict[str, Any] = {}
372
+ if getv(from_object, ['environment']) is not None:
373
+ setv(to_object, ['environment'], getv(from_object, ['environment']))
374
+
375
+ return to_object
376
+
377
+
362
378
  def _Tool_to_mldev(
363
379
  from_object: Union[dict[str, Any], object],
364
380
  parent_object: Optional[dict[str, Any]] = None,
@@ -408,12 +424,18 @@ def _Tool_to_mldev(
408
424
  _UrlContext_to_mldev(getv(from_object, ['url_context']), to_object),
409
425
  )
410
426
 
427
+ if getv(from_object, ['computer_use']) is not None:
428
+ setv(
429
+ to_object,
430
+ ['computerUse'],
431
+ _ToolComputerUse_to_mldev(
432
+ getv(from_object, ['computer_use']), to_object
433
+ ),
434
+ )
435
+
411
436
  if getv(from_object, ['code_execution']) is not None:
412
437
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
413
438
 
414
- if getv(from_object, ['computer_use']) is not None:
415
- setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
416
-
417
439
  return to_object
418
440
 
419
441
 
@@ -1098,6 +1120,13 @@ def _LiveMusicGenerationConfig_to_mldev(
1098
1120
  getv(from_object, ['only_bass_and_drums']),
1099
1121
  )
1100
1122
 
1123
+ if getv(from_object, ['music_generation_mode']) is not None:
1124
+ setv(
1125
+ to_object,
1126
+ ['musicGenerationMode'],
1127
+ getv(from_object, ['music_generation_mode']),
1128
+ )
1129
+
1101
1130
  return to_object
1102
1131
 
1103
1132
 
@@ -1437,6 +1466,9 @@ def _GoogleSearch_to_vertex(
1437
1466
  ),
1438
1467
  )
1439
1468
 
1469
+ if getv(from_object, ['exclude_domains']) is not None:
1470
+ setv(to_object, ['excludeDomains'], getv(from_object, ['exclude_domains']))
1471
+
1440
1472
  return to_object
1441
1473
 
1442
1474
 
@@ -1480,6 +1512,8 @@ def _EnterpriseWebSearch_to_vertex(
1480
1512
  parent_object: Optional[dict[str, Any]] = None,
1481
1513
  ) -> dict[str, Any]:
1482
1514
  to_object: dict[str, Any] = {}
1515
+ if getv(from_object, ['exclude_domains']) is not None:
1516
+ setv(to_object, ['excludeDomains'], getv(from_object, ['exclude_domains']))
1483
1517
 
1484
1518
  return to_object
1485
1519
 
@@ -1559,6 +1593,17 @@ def _UrlContext_to_vertex(
1559
1593
  return to_object
1560
1594
 
1561
1595
 
1596
+ def _ToolComputerUse_to_vertex(
1597
+ from_object: Union[dict[str, Any], object],
1598
+ parent_object: Optional[dict[str, Any]] = None,
1599
+ ) -> dict[str, Any]:
1600
+ to_object: dict[str, Any] = {}
1601
+ if getv(from_object, ['environment']) is not None:
1602
+ setv(to_object, ['environment'], getv(from_object, ['environment']))
1603
+
1604
+ return to_object
1605
+
1606
+
1562
1607
  def _Tool_to_vertex(
1563
1608
  from_object: Union[dict[str, Any], object],
1564
1609
  parent_object: Optional[dict[str, Any]] = None,
@@ -1618,12 +1663,18 @@ def _Tool_to_vertex(
1618
1663
  _UrlContext_to_vertex(getv(from_object, ['url_context']), to_object),
1619
1664
  )
1620
1665
 
1666
+ if getv(from_object, ['computer_use']) is not None:
1667
+ setv(
1668
+ to_object,
1669
+ ['computerUse'],
1670
+ _ToolComputerUse_to_vertex(
1671
+ getv(from_object, ['computer_use']), to_object
1672
+ ),
1673
+ )
1674
+
1621
1675
  if getv(from_object, ['code_execution']) is not None:
1622
1676
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
1623
1677
 
1624
- if getv(from_object, ['computer_use']) is not None:
1625
- setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
1626
-
1627
1678
  return to_object
1628
1679
 
1629
1680
 
@@ -2871,6 +2922,13 @@ def _LiveMusicGenerationConfig_from_mldev(
2871
2922
  getv(from_object, ['onlyBassAndDrums']),
2872
2923
  )
2873
2924
 
2925
+ if getv(from_object, ['musicGenerationMode']) is not None:
2926
+ setv(
2927
+ to_object,
2928
+ ['music_generation_mode'],
2929
+ getv(from_object, ['musicGenerationMode']),
2930
+ )
2931
+
2874
2932
  return to_object
2875
2933
 
2876
2934
 
@@ -312,6 +312,11 @@ def _GoogleSearch_to_mldev(
312
312
  _Interval_to_mldev(getv(from_object, ['time_range_filter']), to_object),
313
313
  )
314
314
 
315
+ if getv(from_object, ['exclude_domains']) is not None:
316
+ raise ValueError(
317
+ 'exclude_domains parameter is not supported in Gemini API.'
318
+ )
319
+
315
320
  return to_object
316
321
 
317
322
 
@@ -359,6 +364,17 @@ def _UrlContext_to_mldev(
359
364
  return to_object
360
365
 
361
366
 
367
+ def _ToolComputerUse_to_mldev(
368
+ from_object: Union[dict[str, Any], object],
369
+ parent_object: Optional[dict[str, Any]] = None,
370
+ ) -> dict[str, Any]:
371
+ to_object: dict[str, Any] = {}
372
+ if getv(from_object, ['environment']) is not None:
373
+ setv(to_object, ['environment'], getv(from_object, ['environment']))
374
+
375
+ return to_object
376
+
377
+
362
378
  def _Tool_to_mldev(
363
379
  from_object: Union[dict[str, Any], object],
364
380
  parent_object: Optional[dict[str, Any]] = None,
@@ -408,12 +424,18 @@ def _Tool_to_mldev(
408
424
  _UrlContext_to_mldev(getv(from_object, ['url_context']), to_object),
409
425
  )
410
426
 
427
+ if getv(from_object, ['computer_use']) is not None:
428
+ setv(
429
+ to_object,
430
+ ['computerUse'],
431
+ _ToolComputerUse_to_mldev(
432
+ getv(from_object, ['computer_use']), to_object
433
+ ),
434
+ )
435
+
411
436
  if getv(from_object, ['code_execution']) is not None:
412
437
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
413
438
 
414
- if getv(from_object, ['computer_use']) is not None:
415
- setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
416
-
417
439
  return to_object
418
440
 
419
441
 
@@ -28,6 +28,7 @@ import types as builtin_types
28
28
  import typing
29
29
  from typing import Any, GenericAlias, List, Optional, Sequence, Union # type: ignore[attr-defined]
30
30
  from ._mcp_utils import mcp_to_gemini_tool
31
+ from ._common import get_value_by_path as getv
31
32
 
32
33
  if typing.TYPE_CHECKING:
33
34
  import PIL.Image
@@ -1224,3 +1225,53 @@ def t_tool_response(
1224
1225
  f'Could not convert input (type "{type(input)}") to '
1225
1226
  '`types.LiveClientToolResponse`'
1226
1227
  ) from e
1228
+
1229
+
1230
+ def t_metrics(
1231
+ metrics: list[types.MetricSubclass]
1232
+ ) -> list[dict[str, Any]]:
1233
+ """Prepares the metric payload for the evaluation request.
1234
+
1235
+ Args:
1236
+ request_dict: The dictionary containing the request details.
1237
+ resolved_metrics: A list of resolved metric objects.
1238
+
1239
+ Returns:
1240
+ The updated request dictionary with the prepared metric payload.
1241
+ """
1242
+ metrics_payload = []
1243
+
1244
+ for metric in metrics:
1245
+ metric_payload_item: dict[str, Any] = {}
1246
+ metric_payload_item['aggregation_metrics'] = [
1247
+ 'AVERAGE',
1248
+ 'STANDARD_DEVIATION',
1249
+ ]
1250
+
1251
+ metric_name = getv(metric, ['name']).lower()
1252
+
1253
+ if metric_name == 'exact_match':
1254
+ metric_payload_item['exact_match_spec'] = {}
1255
+ elif metric_name == 'bleu':
1256
+ metric_payload_item['bleu_spec'] = {}
1257
+ elif metric_name.startswith('rouge'):
1258
+ rouge_type = metric_name.replace("_", "")
1259
+ metric_payload_item['rouge_spec'] = {'rouge_type': rouge_type}
1260
+
1261
+ elif hasattr(metric, 'prompt_template') and metric.prompt_template:
1262
+ pointwise_spec = {'metric_prompt_template': metric.prompt_template}
1263
+ system_instruction = getv(metric, ['judge_model_system_instruction'])
1264
+ if system_instruction:
1265
+ pointwise_spec['system_instruction'] = system_instruction
1266
+ return_raw_output = getv(metric, ['return_raw_output'])
1267
+ if return_raw_output:
1268
+ pointwise_spec['custom_output_format_config'] = { # type: ignore[assignment]
1269
+ 'return_raw_output': return_raw_output
1270
+ }
1271
+ metric_payload_item['pointwise_metric_spec'] = pointwise_spec
1272
+ else:
1273
+ raise ValueError(
1274
+ 'Unsupported metric type or invalid metric name:' f' {metric_name}'
1275
+ )
1276
+ metrics_payload.append(metric_payload_item)
1277
+ return metrics_payload
google/genai/batches.py CHANGED
@@ -338,6 +338,11 @@ def _GoogleSearch_to_mldev(
338
338
  _Interval_to_mldev(getv(from_object, ['time_range_filter']), to_object),
339
339
  )
340
340
 
341
+ if getv(from_object, ['exclude_domains']) is not None:
342
+ raise ValueError(
343
+ 'exclude_domains parameter is not supported in Gemini API.'
344
+ )
345
+
341
346
  return to_object
342
347
 
343
348
 
@@ -385,6 +390,17 @@ def _UrlContext_to_mldev(
385
390
  return to_object
386
391
 
387
392
 
393
+ def _ToolComputerUse_to_mldev(
394
+ from_object: Union[dict[str, Any], object],
395
+ parent_object: Optional[dict[str, Any]] = None,
396
+ ) -> dict[str, Any]:
397
+ to_object: dict[str, Any] = {}
398
+ if getv(from_object, ['environment']) is not None:
399
+ setv(to_object, ['environment'], getv(from_object, ['environment']))
400
+
401
+ return to_object
402
+
403
+
388
404
  def _Tool_to_mldev(
389
405
  from_object: Union[dict[str, Any], object],
390
406
  parent_object: Optional[dict[str, Any]] = None,
@@ -434,12 +450,18 @@ def _Tool_to_mldev(
434
450
  _UrlContext_to_mldev(getv(from_object, ['url_context']), to_object),
435
451
  )
436
452
 
453
+ if getv(from_object, ['computer_use']) is not None:
454
+ setv(
455
+ to_object,
456
+ ['computerUse'],
457
+ _ToolComputerUse_to_mldev(
458
+ getv(from_object, ['computer_use']), to_object
459
+ ),
460
+ )
461
+
437
462
  if getv(from_object, ['code_execution']) is not None:
438
463
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
439
464
 
440
- if getv(from_object, ['computer_use']) is not None:
441
- setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
442
-
443
465
  return to_object
444
466
 
445
467
 
@@ -1492,6 +1514,9 @@ def _GenerateContentResponse_from_mldev(
1492
1514
  if getv(from_object, ['promptFeedback']) is not None:
1493
1515
  setv(to_object, ['prompt_feedback'], getv(from_object, ['promptFeedback']))
1494
1516
 
1517
+ if getv(from_object, ['responseId']) is not None:
1518
+ setv(to_object, ['response_id'], getv(from_object, ['responseId']))
1519
+
1495
1520
  if getv(from_object, ['usageMetadata']) is not None:
1496
1521
  setv(to_object, ['usage_metadata'], getv(from_object, ['usageMetadata']))
1497
1522
 
@@ -1648,6 +1673,11 @@ def _DeleteResourceJob_from_mldev(
1648
1673
  parent_object: Optional[dict[str, Any]] = None,
1649
1674
  ) -> dict[str, Any]:
1650
1675
  to_object: dict[str, Any] = {}
1676
+ if getv(from_object, ['sdkHttpResponse']) is not None:
1677
+ setv(
1678
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
1679
+ )
1680
+
1651
1681
  if getv(from_object, ['name']) is not None:
1652
1682
  setv(to_object, ['name'], getv(from_object, ['name']))
1653
1683
 
@@ -1815,6 +1845,11 @@ def _DeleteResourceJob_from_vertex(
1815
1845
  parent_object: Optional[dict[str, Any]] = None,
1816
1846
  ) -> dict[str, Any]:
1817
1847
  to_object: dict[str, Any] = {}
1848
+ if getv(from_object, ['sdkHttpResponse']) is not None:
1849
+ setv(
1850
+ to_object, ['sdk_http_response'], getv(from_object, ['sdkHttpResponse'])
1851
+ )
1852
+
1818
1853
  if getv(from_object, ['name']) is not None:
1819
1854
  setv(to_object, ['name'], getv(from_object, ['name']))
1820
1855
 
@@ -2186,7 +2221,9 @@ class Batches(_api_module.BaseModule):
2186
2221
  return_value = types.DeleteResourceJob._from_response(
2187
2222
  response=response_dict, kwargs=parameter_model.model_dump()
2188
2223
  )
2189
-
2224
+ return_value.sdk_http_response = types.HttpResponse(
2225
+ headers=response.headers
2226
+ )
2190
2227
  self._api_client._verify_response(return_value)
2191
2228
  return return_value
2192
2229
 
@@ -2619,7 +2656,9 @@ class AsyncBatches(_api_module.BaseModule):
2619
2656
  return_value = types.DeleteResourceJob._from_response(
2620
2657
  response=response_dict, kwargs=parameter_model.model_dump()
2621
2658
  )
2622
-
2659
+ return_value.sdk_http_response = types.HttpResponse(
2660
+ headers=response.headers
2661
+ )
2623
2662
  self._api_client._verify_response(return_value)
2624
2663
  return return_value
2625
2664