google-genai 1.46.0__py3-none-any.whl → 1.48.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.
@@ -599,7 +599,7 @@ class BaseApiClient:
599
599
  # Handle when to use Vertex AI in express mode (api key).
600
600
  # Explicit initializer arguments are already validated above.
601
601
  if self.vertexai:
602
- if credentials:
602
+ if credentials and env_api_key:
603
603
  # Explicit credentials take precedence over implicit api_key.
604
604
  logger.info(
605
605
  'The user provided Google Cloud credentials will take precedence'
@@ -629,6 +629,9 @@ class BaseApiClient:
629
629
  )
630
630
  self.api_key = None
631
631
 
632
+ if not self.location and not self.api_key:
633
+ self.location = 'global'
634
+
632
635
  self.custom_base_url = (
633
636
  validated_http_options.base_url
634
637
  if validated_http_options.base_url
@@ -650,16 +653,19 @@ class BaseApiClient:
650
653
  if not has_sufficient_auth and not self.custom_base_url:
651
654
  # Skip sufficient auth check if base url is provided in http options.
652
655
  raise ValueError(
653
- 'Project and location or API key must be set when using the Vertex '
656
+ 'Project or API key must be set when using the Vertex '
654
657
  'AI API.'
655
658
  )
656
659
  if self.api_key or self.location == 'global':
657
660
  self._http_options.base_url = f'https://aiplatform.googleapis.com/'
658
- elif self.custom_base_url and not has_sufficient_auth:
661
+ elif self.custom_base_url and not ((project and location) or api_key):
659
662
  # Avoid setting default base url and api version if base_url provided.
660
663
  # API gateway proxy can use the auth in custom headers, not url.
661
664
  # Enable custom url if auth is not sufficient.
662
665
  self._http_options.base_url = self.custom_base_url
666
+ # Clear project and location if base_url is provided.
667
+ self.project = None
668
+ self.location = None
663
669
  else:
664
670
  self._http_options.base_url = (
665
671
  f'https://{self.location}-aiplatform.googleapis.com/'
@@ -703,10 +709,15 @@ class BaseApiClient:
703
709
  else:
704
710
  self._async_httpx_client = AsyncHttpxClient(**async_client_args)
705
711
  if self._use_aiohttp():
706
- # Do it once at the genai.Client level. Share among all requests.
707
- self._async_client_session_request_args = self._ensure_aiohttp_ssl_ctx(
708
- self._http_options
709
- )
712
+ try:
713
+ import aiohttp # pylint: disable=g-import-not-at-top
714
+ # Do it once at the genai.Client level. Share among all requests.
715
+ self._async_client_session_request_args = self._ensure_aiohttp_ssl_ctx(
716
+ self._http_options
717
+ )
718
+ except ImportError:
719
+ pass
720
+
710
721
  # Initialize the aiohttp client session.
711
722
  self._aiohttp_session: Optional[aiohttp.ClientSession] = None
712
723
 
@@ -911,6 +922,7 @@ class BaseApiClient:
911
922
  has_aiohttp
912
923
  and (self._http_options.async_client_args or {}).get('transport')
913
924
  is None
925
+ and (self._http_options.httpx_async_client is None)
914
926
  )
915
927
 
916
928
  def _websocket_base_url(self) -> str:
@@ -1056,11 +1068,16 @@ class BaseApiClient:
1056
1068
  _common.recursive_dict_update(
1057
1069
  request_dict, patched_http_options.extra_body
1058
1070
  )
1059
-
1060
- url = join_url_path(
1061
- base_url,
1062
- versioned_path,
1063
- )
1071
+ url = base_url
1072
+ if (
1073
+ not self.custom_base_url
1074
+ or (self.project and self.location)
1075
+ or self.api_key
1076
+ ):
1077
+ url = join_url_path(
1078
+ base_url,
1079
+ versioned_path,
1080
+ )
1064
1081
 
1065
1082
  if self.api_key and self.api_key.startswith('auth_tokens/'):
1066
1083
  raise EphemeralTokenAPIKeyError(
@@ -1807,11 +1824,17 @@ class BaseApiClient:
1807
1824
  """
1808
1825
 
1809
1826
  try:
1810
- self.close()
1827
+ # Let users close the custom client explicitly by themselves. Otherwise,
1828
+ # close the client when the object is garbage collected.
1829
+ if not self._http_options.httpx_client:
1830
+ self.close()
1811
1831
  except Exception: # pylint: disable=broad-except
1812
1832
  pass
1813
1833
 
1814
1834
  try:
1815
- asyncio.get_running_loop().create_task(self.aclose())
1835
+ # Let users close the custom client explicitly by themselves. Otherwise,
1836
+ # close the client when the object is garbage collected.
1837
+ if not self._http_options.httpx_async_client:
1838
+ asyncio.get_running_loop().create_task(self.aclose())
1816
1839
  except Exception: # pylint: disable=broad-except
1817
- pass
1840
+ pass
@@ -15,6 +15,7 @@
15
15
 
16
16
  """Extra utils depending on types that are shared between sync and async modules."""
17
17
 
18
+ import asyncio
18
19
  import inspect
19
20
  import io
20
21
  import logging
@@ -117,6 +118,35 @@ def format_destination(
117
118
  return config
118
119
 
119
120
 
121
+ def find_afc_incompatible_tool_indexes(
122
+ config: Optional[types.GenerateContentConfigOrDict] = None,
123
+ ) -> list[int]:
124
+ """Checks if the config contains any AFC incompatible tools.
125
+
126
+ A `types.Tool` object that contains `function_declarations` is considered a
127
+ non-AFC tool for this execution path.
128
+
129
+ Args:
130
+ config: The GenerateContentConfig to check for incompatible tools.
131
+
132
+ Returns:
133
+ A list of indexes of the incompatible tools in the config.
134
+ """
135
+ if not config:
136
+ return []
137
+ config_model = _create_generate_content_config_model(config)
138
+ incompatible_tools_indexes: list[int] = []
139
+
140
+ if not config_model or not config_model.tools:
141
+ return incompatible_tools_indexes
142
+
143
+ for index, tool in enumerate(config_model.tools):
144
+ if isinstance(tool, types.Tool) and tool.function_declarations:
145
+ incompatible_tools_indexes.append(index)
146
+
147
+ return incompatible_tools_indexes
148
+
149
+
120
150
  def get_function_map(
121
151
  config: Optional[types.GenerateContentConfigOrDict] = None,
122
152
  mcp_to_genai_tool_adapters: Optional[
@@ -371,7 +401,9 @@ async def get_function_response_parts_async(
371
401
  }
372
402
  else:
373
403
  func_response = {
374
- 'result': invoke_function_from_dict_args(args, func)
404
+ 'result': await asyncio.to_thread(
405
+ invoke_function_from_dict_args, args, func
406
+ )
375
407
  }
376
408
  except Exception as e: # pylint: disable=broad-except
377
409
  func_response = {'error': str(e)}
@@ -536,13 +568,14 @@ async def parse_config_for_mcp_sessions(
536
568
  def append_chunk_contents(
537
569
  contents: Union[types.ContentListUnion, types.ContentListUnionDict],
538
570
  chunk: types.GenerateContentResponse,
539
- ) -> None:
540
- """Appends the contents of the chunk to the contents list."""
571
+ ) -> Union[types.ContentListUnion, types.ContentListUnionDict]:
572
+ """Appends the contents of the chunk to the contents list and returns it."""
541
573
  if chunk is not None and chunk.candidates is not None:
542
574
  chunk_content = chunk.candidates[0].content
543
575
  contents = t.t_contents(contents) # type: ignore[assignment]
544
576
  if isinstance(contents, list) and chunk_content is not None:
545
577
  contents.append(chunk_content) # type: ignore[arg-type]
578
+ return contents
546
579
 
547
580
 
548
581
  def prepare_resumable_upload(
@@ -611,4 +644,8 @@ def prepare_resumable_upload(
611
644
  'X-Goog-Upload-Header-Content-Type': f'{mime_type}',
612
645
  },
613
646
  )
647
+ if isinstance(file, (str, os.PathLike)):
648
+ if http_options.headers is None:
649
+ http_options.headers = {}
650
+ http_options.headers['X-Goog-Upload-File-Name'] = os.path.basename(file)
614
651
  return http_options, size_bytes, mime_type
@@ -28,12 +28,12 @@ def _Blob_to_mldev(
28
28
  parent_object: Optional[dict[str, Any]] = None,
29
29
  ) -> dict[str, Any]:
30
30
  to_object: dict[str, Any] = {}
31
- if getv(from_object, ['display_name']) is not None:
32
- raise ValueError('display_name parameter is not supported in Gemini API.')
33
-
34
31
  if getv(from_object, ['data']) is not None:
35
32
  setv(to_object, ['data'], getv(from_object, ['data']))
36
33
 
34
+ if getv(from_object, ['display_name']) is not None:
35
+ raise ValueError('display_name parameter is not supported in Gemini API.')
36
+
37
37
  if getv(from_object, ['mime_type']) is not None:
38
38
  setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
39
39
 
@@ -253,16 +253,21 @@ def _GoogleSearch_to_mldev(
253
253
  parent_object: Optional[dict[str, Any]] = None,
254
254
  ) -> dict[str, Any]:
255
255
  to_object: dict[str, Any] = {}
256
- if getv(from_object, ['time_range_filter']) is not None:
257
- setv(
258
- to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
259
- )
260
-
261
256
  if getv(from_object, ['exclude_domains']) is not None:
262
257
  raise ValueError(
263
258
  'exclude_domains parameter is not supported in Gemini API.'
264
259
  )
265
260
 
261
+ if getv(from_object, ['blocking_confidence']) is not None:
262
+ raise ValueError(
263
+ 'blocking_confidence parameter is not supported in Gemini API.'
264
+ )
265
+
266
+ if getv(from_object, ['time_range_filter']) is not None:
267
+ setv(
268
+ to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
269
+ )
270
+
266
271
  return to_object
267
272
 
268
273
 
@@ -1156,19 +1161,19 @@ def _Part_to_mldev(
1156
1161
  parent_object: Optional[dict[str, Any]] = None,
1157
1162
  ) -> dict[str, Any]:
1158
1163
  to_object: dict[str, Any] = {}
1159
- if getv(from_object, ['video_metadata']) is not None:
1160
- setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
1161
-
1162
- if getv(from_object, ['thought']) is not None:
1163
- setv(to_object, ['thought'], getv(from_object, ['thought']))
1164
+ if getv(from_object, ['function_call']) is not None:
1165
+ setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
1164
1166
 
1165
- if getv(from_object, ['inline_data']) is not None:
1167
+ if getv(from_object, ['code_execution_result']) is not None:
1166
1168
  setv(
1167
1169
  to_object,
1168
- ['inlineData'],
1169
- _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
1170
+ ['codeExecutionResult'],
1171
+ getv(from_object, ['code_execution_result']),
1170
1172
  )
1171
1173
 
1174
+ if getv(from_object, ['executable_code']) is not None:
1175
+ setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
1176
+
1172
1177
  if getv(from_object, ['file_data']) is not None:
1173
1178
  setv(
1174
1179
  to_object,
@@ -1176,35 +1181,35 @@ def _Part_to_mldev(
1176
1181
  _FileData_to_mldev(getv(from_object, ['file_data']), to_object),
1177
1182
  )
1178
1183
 
1179
- if getv(from_object, ['thought_signature']) is not None:
1184
+ if getv(from_object, ['function_response']) is not None:
1180
1185
  setv(
1181
1186
  to_object,
1182
- ['thoughtSignature'],
1183
- getv(from_object, ['thought_signature']),
1187
+ ['functionResponse'],
1188
+ getv(from_object, ['function_response']),
1184
1189
  )
1185
1190
 
1186
- if getv(from_object, ['function_call']) is not None:
1187
- setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
1188
-
1189
- if getv(from_object, ['code_execution_result']) is not None:
1191
+ if getv(from_object, ['inline_data']) is not None:
1190
1192
  setv(
1191
1193
  to_object,
1192
- ['codeExecutionResult'],
1193
- getv(from_object, ['code_execution_result']),
1194
+ ['inlineData'],
1195
+ _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
1194
1196
  )
1195
1197
 
1196
- if getv(from_object, ['executable_code']) is not None:
1197
- setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
1198
+ if getv(from_object, ['text']) is not None:
1199
+ setv(to_object, ['text'], getv(from_object, ['text']))
1198
1200
 
1199
- if getv(from_object, ['function_response']) is not None:
1201
+ if getv(from_object, ['thought']) is not None:
1202
+ setv(to_object, ['thought'], getv(from_object, ['thought']))
1203
+
1204
+ if getv(from_object, ['thought_signature']) is not None:
1200
1205
  setv(
1201
1206
  to_object,
1202
- ['functionResponse'],
1203
- getv(from_object, ['function_response']),
1207
+ ['thoughtSignature'],
1208
+ getv(from_object, ['thought_signature']),
1204
1209
  )
1205
1210
 
1206
- if getv(from_object, ['text']) is not None:
1207
- setv(to_object, ['text'], getv(from_object, ['text']))
1211
+ if getv(from_object, ['video_metadata']) is not None:
1212
+ setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
1208
1213
 
1209
1214
  return to_object
1210
1215
 
@@ -1228,6 +1233,9 @@ def _SpeechConfig_to_vertex(
1228
1233
  parent_object: Optional[dict[str, Any]] = None,
1229
1234
  ) -> dict[str, Any]:
1230
1235
  to_object: dict[str, Any] = {}
1236
+ if getv(from_object, ['language_code']) is not None:
1237
+ setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
1238
+
1231
1239
  if getv(from_object, ['voice_config']) is not None:
1232
1240
  setv(to_object, ['voiceConfig'], getv(from_object, ['voice_config']))
1233
1241
 
@@ -1236,9 +1244,6 @@ def _SpeechConfig_to_vertex(
1236
1244
  'multi_speaker_voice_config parameter is not supported in Vertex AI.'
1237
1245
  )
1238
1246
 
1239
- if getv(from_object, ['language_code']) is not None:
1240
- setv(to_object, ['languageCode'], getv(from_object, ['language_code']))
1241
-
1242
1247
  return to_object
1243
1248
 
1244
1249
 
@@ -1257,13 +1262,6 @@ def _Tool_to_mldev(
1257
1262
  if getv(from_object, ['retrieval']) is not None:
1258
1263
  raise ValueError('retrieval parameter is not supported in Gemini API.')
1259
1264
 
1260
- if getv(from_object, ['google_search']) is not None:
1261
- setv(
1262
- to_object,
1263
- ['googleSearch'],
1264
- _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
1265
- )
1266
-
1267
1265
  if getv(from_object, ['google_search_retrieval']) is not None:
1268
1266
  setv(
1269
1267
  to_object,
@@ -1271,11 +1269,6 @@ def _Tool_to_mldev(
1271
1269
  getv(from_object, ['google_search_retrieval']),
1272
1270
  )
1273
1271
 
1274
- if getv(from_object, ['enterprise_web_search']) is not None:
1275
- raise ValueError(
1276
- 'enterprise_web_search parameter is not supported in Gemini API.'
1277
- )
1278
-
1279
1272
  if getv(from_object, ['google_maps']) is not None:
1280
1273
  setv(
1281
1274
  to_object,
@@ -1283,15 +1276,27 @@ def _Tool_to_mldev(
1283
1276
  _GoogleMaps_to_mldev(getv(from_object, ['google_maps']), to_object),
1284
1277
  )
1285
1278
 
1286
- if getv(from_object, ['url_context']) is not None:
1287
- setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
1288
-
1289
1279
  if getv(from_object, ['computer_use']) is not None:
1290
1280
  setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
1291
1281
 
1292
1282
  if getv(from_object, ['code_execution']) is not None:
1293
1283
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
1294
1284
 
1285
+ if getv(from_object, ['enterprise_web_search']) is not None:
1286
+ raise ValueError(
1287
+ 'enterprise_web_search parameter is not supported in Gemini API.'
1288
+ )
1289
+
1290
+ if getv(from_object, ['google_search']) is not None:
1291
+ setv(
1292
+ to_object,
1293
+ ['googleSearch'],
1294
+ _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
1295
+ )
1296
+
1297
+ if getv(from_object, ['url_context']) is not None:
1298
+ setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
1299
+
1295
1300
  return to_object
1296
1301
 
1297
1302
 
@@ -1313,9 +1318,6 @@ def _Tool_to_vertex(
1313
1318
  if getv(from_object, ['retrieval']) is not None:
1314
1319
  setv(to_object, ['retrieval'], getv(from_object, ['retrieval']))
1315
1320
 
1316
- if getv(from_object, ['google_search']) is not None:
1317
- setv(to_object, ['googleSearch'], getv(from_object, ['google_search']))
1318
-
1319
1321
  if getv(from_object, ['google_search_retrieval']) is not None:
1320
1322
  setv(
1321
1323
  to_object,
@@ -1323,6 +1325,15 @@ def _Tool_to_vertex(
1323
1325
  getv(from_object, ['google_search_retrieval']),
1324
1326
  )
1325
1327
 
1328
+ if getv(from_object, ['google_maps']) is not None:
1329
+ setv(to_object, ['googleMaps'], getv(from_object, ['google_maps']))
1330
+
1331
+ if getv(from_object, ['computer_use']) is not None:
1332
+ setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
1333
+
1334
+ if getv(from_object, ['code_execution']) is not None:
1335
+ setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
1336
+
1326
1337
  if getv(from_object, ['enterprise_web_search']) is not None:
1327
1338
  setv(
1328
1339
  to_object,
@@ -1330,18 +1341,12 @@ def _Tool_to_vertex(
1330
1341
  getv(from_object, ['enterprise_web_search']),
1331
1342
  )
1332
1343
 
1333
- if getv(from_object, ['google_maps']) is not None:
1334
- setv(to_object, ['googleMaps'], getv(from_object, ['google_maps']))
1344
+ if getv(from_object, ['google_search']) is not None:
1345
+ setv(to_object, ['googleSearch'], getv(from_object, ['google_search']))
1335
1346
 
1336
1347
  if getv(from_object, ['url_context']) is not None:
1337
1348
  setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
1338
1349
 
1339
- if getv(from_object, ['computer_use']) is not None:
1340
- setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
1341
-
1342
- if getv(from_object, ['code_execution']) is not None:
1343
- setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
1344
-
1345
1350
  return to_object
1346
1351
 
1347
1352
 
@@ -28,12 +28,12 @@ def _Blob_to_mldev(
28
28
  parent_object: Optional[dict[str, Any]] = None,
29
29
  ) -> dict[str, Any]:
30
30
  to_object: dict[str, Any] = {}
31
- if getv(from_object, ['display_name']) is not None:
32
- raise ValueError('display_name parameter is not supported in Gemini API.')
33
-
34
31
  if getv(from_object, ['data']) is not None:
35
32
  setv(to_object, ['data'], getv(from_object, ['data']))
36
33
 
34
+ if getv(from_object, ['display_name']) is not None:
35
+ raise ValueError('display_name parameter is not supported in Gemini API.')
36
+
37
37
  if getv(from_object, ['mime_type']) is not None:
38
38
  setv(to_object, ['mimeType'], getv(from_object, ['mime_type']))
39
39
 
@@ -167,16 +167,21 @@ def _GoogleSearch_to_mldev(
167
167
  parent_object: Optional[dict[str, Any]] = None,
168
168
  ) -> dict[str, Any]:
169
169
  to_object: dict[str, Any] = {}
170
- if getv(from_object, ['time_range_filter']) is not None:
171
- setv(
172
- to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
173
- )
174
-
175
170
  if getv(from_object, ['exclude_domains']) is not None:
176
171
  raise ValueError(
177
172
  'exclude_domains parameter is not supported in Gemini API.'
178
173
  )
179
174
 
175
+ if getv(from_object, ['blocking_confidence']) is not None:
176
+ raise ValueError(
177
+ 'blocking_confidence parameter is not supported in Gemini API.'
178
+ )
179
+
180
+ if getv(from_object, ['time_range_filter']) is not None:
181
+ setv(
182
+ to_object, ['timeRangeFilter'], getv(from_object, ['time_range_filter'])
183
+ )
184
+
180
185
  return to_object
181
186
 
182
187
 
@@ -360,19 +365,19 @@ def _Part_to_mldev(
360
365
  parent_object: Optional[dict[str, Any]] = None,
361
366
  ) -> dict[str, Any]:
362
367
  to_object: dict[str, Any] = {}
363
- if getv(from_object, ['video_metadata']) is not None:
364
- setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
365
-
366
- if getv(from_object, ['thought']) is not None:
367
- setv(to_object, ['thought'], getv(from_object, ['thought']))
368
+ if getv(from_object, ['function_call']) is not None:
369
+ setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
368
370
 
369
- if getv(from_object, ['inline_data']) is not None:
371
+ if getv(from_object, ['code_execution_result']) is not None:
370
372
  setv(
371
373
  to_object,
372
- ['inlineData'],
373
- _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
374
+ ['codeExecutionResult'],
375
+ getv(from_object, ['code_execution_result']),
374
376
  )
375
377
 
378
+ if getv(from_object, ['executable_code']) is not None:
379
+ setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
380
+
376
381
  if getv(from_object, ['file_data']) is not None:
377
382
  setv(
378
383
  to_object,
@@ -380,35 +385,35 @@ def _Part_to_mldev(
380
385
  _FileData_to_mldev(getv(from_object, ['file_data']), to_object),
381
386
  )
382
387
 
383
- if getv(from_object, ['thought_signature']) is not None:
388
+ if getv(from_object, ['function_response']) is not None:
384
389
  setv(
385
390
  to_object,
386
- ['thoughtSignature'],
387
- getv(from_object, ['thought_signature']),
391
+ ['functionResponse'],
392
+ getv(from_object, ['function_response']),
388
393
  )
389
394
 
390
- if getv(from_object, ['function_call']) is not None:
391
- setv(to_object, ['functionCall'], getv(from_object, ['function_call']))
392
-
393
- if getv(from_object, ['code_execution_result']) is not None:
395
+ if getv(from_object, ['inline_data']) is not None:
394
396
  setv(
395
397
  to_object,
396
- ['codeExecutionResult'],
397
- getv(from_object, ['code_execution_result']),
398
+ ['inlineData'],
399
+ _Blob_to_mldev(getv(from_object, ['inline_data']), to_object),
398
400
  )
399
401
 
400
- if getv(from_object, ['executable_code']) is not None:
401
- setv(to_object, ['executableCode'], getv(from_object, ['executable_code']))
402
+ if getv(from_object, ['text']) is not None:
403
+ setv(to_object, ['text'], getv(from_object, ['text']))
402
404
 
403
- if getv(from_object, ['function_response']) is not None:
405
+ if getv(from_object, ['thought']) is not None:
406
+ setv(to_object, ['thought'], getv(from_object, ['thought']))
407
+
408
+ if getv(from_object, ['thought_signature']) is not None:
404
409
  setv(
405
410
  to_object,
406
- ['functionResponse'],
407
- getv(from_object, ['function_response']),
411
+ ['thoughtSignature'],
412
+ getv(from_object, ['thought_signature']),
408
413
  )
409
414
 
410
- if getv(from_object, ['text']) is not None:
411
- setv(to_object, ['text'], getv(from_object, ['text']))
415
+ if getv(from_object, ['video_metadata']) is not None:
416
+ setv(to_object, ['videoMetadata'], getv(from_object, ['video_metadata']))
412
417
 
413
418
  return to_object
414
419
 
@@ -442,13 +447,6 @@ def _Tool_to_mldev(
442
447
  if getv(from_object, ['retrieval']) is not None:
443
448
  raise ValueError('retrieval parameter is not supported in Gemini API.')
444
449
 
445
- if getv(from_object, ['google_search']) is not None:
446
- setv(
447
- to_object,
448
- ['googleSearch'],
449
- _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
450
- )
451
-
452
450
  if getv(from_object, ['google_search_retrieval']) is not None:
453
451
  setv(
454
452
  to_object,
@@ -456,11 +454,6 @@ def _Tool_to_mldev(
456
454
  getv(from_object, ['google_search_retrieval']),
457
455
  )
458
456
 
459
- if getv(from_object, ['enterprise_web_search']) is not None:
460
- raise ValueError(
461
- 'enterprise_web_search parameter is not supported in Gemini API.'
462
- )
463
-
464
457
  if getv(from_object, ['google_maps']) is not None:
465
458
  setv(
466
459
  to_object,
@@ -468,13 +461,25 @@ def _Tool_to_mldev(
468
461
  _GoogleMaps_to_mldev(getv(from_object, ['google_maps']), to_object),
469
462
  )
470
463
 
471
- if getv(from_object, ['url_context']) is not None:
472
- setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
473
-
474
464
  if getv(from_object, ['computer_use']) is not None:
475
465
  setv(to_object, ['computerUse'], getv(from_object, ['computer_use']))
476
466
 
477
467
  if getv(from_object, ['code_execution']) is not None:
478
468
  setv(to_object, ['codeExecution'], getv(from_object, ['code_execution']))
479
469
 
470
+ if getv(from_object, ['enterprise_web_search']) is not None:
471
+ raise ValueError(
472
+ 'enterprise_web_search parameter is not supported in Gemini API.'
473
+ )
474
+
475
+ if getv(from_object, ['google_search']) is not None:
476
+ setv(
477
+ to_object,
478
+ ['googleSearch'],
479
+ _GoogleSearch_to_mldev(getv(from_object, ['google_search']), to_object),
480
+ )
481
+
482
+ if getv(from_object, ['url_context']) is not None:
483
+ setv(to_object, ['urlContext'], getv(from_object, ['url_context']))
484
+
480
485
  return to_object
@@ -91,7 +91,16 @@ def _is_duck_type_of(obj: Any, cls: type[pydantic.BaseModel]) -> bool:
91
91
  return False
92
92
 
93
93
  # Check if the object has all of the Pydantic model's defined fields.
94
- return all(hasattr(obj, field) for field in cls.model_fields)
94
+ all_matched = all(hasattr(obj, field) for field in cls.model_fields)
95
+ if not all_matched and isinstance(obj, pydantic.BaseModel):
96
+ # Check the other way around if obj is a Pydantic model.
97
+ # Check if the Pydantic model has all of the object's defined fields.
98
+ try:
99
+ obj_private = cls()
100
+ all_matched = all(hasattr(obj_private, f) for f in type(obj).model_fields)
101
+ except ValueError:
102
+ return False
103
+ return all_matched
95
104
 
96
105
 
97
106
  def _resource_name(