langchain-google-genai 2.0.8__py3-none-any.whl → 2.0.10__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.

Potentially problematic release.


This version of langchain-google-genai might be problematic. Click here for more details.

@@ -235,13 +235,16 @@ def _format_base_tool_to_function_declaration(
235
235
  ),
236
236
  )
237
237
 
238
- if issubclass(tool.args_schema, BaseModel):
238
+ if isinstance(tool.args_schema, dict):
239
+ schema = tool.args_schema
240
+ elif issubclass(tool.args_schema, BaseModel):
239
241
  schema = tool.args_schema.model_json_schema()
240
242
  elif issubclass(tool.args_schema, BaseModelV1):
241
243
  schema = tool.args_schema.schema()
242
244
  else:
243
245
  raise NotImplementedError(
244
- f"args_schema must be a Pydantic BaseModel, got {tool.args_schema}."
246
+ "args_schema must be a Pydantic BaseModel or JSON schema, "
247
+ f"got {tool.args_schema}."
245
248
  )
246
249
  parameters = _dict_to_gapic_schema(schema)
247
250
 
@@ -301,10 +304,18 @@ def _get_properties_from_schema(schema: Dict) -> Dict[str, Any]:
301
304
  continue
302
305
  properties_item: Dict[str, Union[str, int, Dict, List]] = {}
303
306
  if v.get("type") or v.get("anyOf") or v.get("type_"):
304
- properties_item["type_"] = _get_type_from_schema(v)
307
+ item_type_ = _get_type_from_schema(v)
308
+ properties_item["type_"] = item_type_
305
309
  if _is_nullable_schema(v):
306
310
  properties_item["nullable"] = True
307
311
 
312
+ # Replace `v` with chosen definition for array / object json types
313
+ any_of_types = v.get("anyOf")
314
+ if any_of_types and item_type_ in [glm.Type.ARRAY, glm.Type.OBJECT]:
315
+ json_type_ = "array" if item_type_ == glm.Type.ARRAY else "object"
316
+ # Use Index -1 for consistency with `_get_nullable_type_from_schema`
317
+ v = [val for val in any_of_types if val.get("type") == json_type_][-1]
318
+
308
319
  if v.get("enum"):
309
320
  properties_item["enum"] = v["enum"]
310
321
 
@@ -301,6 +301,53 @@ def _convert_to_parts(
301
301
  return parts
302
302
 
303
303
 
304
+ def _convert_tool_message_to_part(
305
+ message: ToolMessage | FunctionMessage, name: Optional[str] = None
306
+ ) -> Part:
307
+ """Converts a tool or function message to a google part."""
308
+ # Legacy agent stores tool name in message.additional_kwargs instead of message.name
309
+ name = message.name or name or message.additional_kwargs.get("name")
310
+ response: Any
311
+ if not isinstance(message.content, str):
312
+ response = message.content
313
+ else:
314
+ try:
315
+ response = json.loads(message.content)
316
+ except json.JSONDecodeError:
317
+ response = message.content # leave as str representation
318
+ part = Part(
319
+ function_response=FunctionResponse(
320
+ name=name,
321
+ response=(
322
+ {"output": response} if not isinstance(response, dict) else response
323
+ ),
324
+ )
325
+ )
326
+ return part
327
+
328
+
329
+ def _get_ai_message_tool_messages_parts(
330
+ tool_messages: Sequence[ToolMessage], ai_message: AIMessage
331
+ ) -> list[Part]:
332
+ """
333
+ Finds relevant tool messages for the AI message and converts them to a single
334
+ list of Parts.
335
+ """
336
+ # We are interested only in the tool messages that are part of the AI message
337
+ tool_calls_ids = {tool_call["id"]: tool_call for tool_call in ai_message.tool_calls}
338
+ parts = []
339
+ for i, message in enumerate(tool_messages):
340
+ if not tool_calls_ids:
341
+ break
342
+ if message.tool_call_id in tool_calls_ids:
343
+ tool_call = tool_calls_ids[message.tool_call_id]
344
+ part = _convert_tool_message_to_part(message, name=tool_call.get("name"))
345
+ parts.append(part)
346
+ # remove the id from the dict, so that we do not iterate over it again
347
+ tool_calls_ids.pop(message.tool_call_id)
348
+ return parts
349
+
350
+
304
351
  def _parse_chat_history(
305
352
  input_messages: Sequence[BaseMessage], convert_system_message_to_human: bool = False
306
353
  ) -> Tuple[Optional[Content], List[Content]]:
@@ -310,14 +357,26 @@ def _parse_chat_history(
310
357
  warnings.warn("Convert_system_message_to_human will be deprecated!")
311
358
 
312
359
  system_instruction: Optional[Content] = None
313
- for i, message in enumerate(input_messages):
314
- if i == 0 and isinstance(message, SystemMessage):
315
- system_instruction = Content(parts=_convert_to_parts(message.content))
360
+ messages_without_tool_messages = [
361
+ message for message in input_messages if not isinstance(message, ToolMessage)
362
+ ]
363
+ tool_messages = [
364
+ message for message in input_messages if isinstance(message, ToolMessage)
365
+ ]
366
+ for i, message in enumerate(messages_without_tool_messages):
367
+ if isinstance(message, SystemMessage):
368
+ system_parts = _convert_to_parts(message.content)
369
+ if i == 0:
370
+ system_instruction = Content(parts=system_parts)
371
+ elif system_instruction is not None:
372
+ system_instruction.parts.extend(system_parts)
373
+ else:
374
+ pass
316
375
  continue
317
376
  elif isinstance(message, AIMessage):
318
377
  role = "model"
319
378
  if message.tool_calls:
320
- parts = []
379
+ ai_message_parts = []
321
380
  for tool_call in message.tool_calls:
322
381
  function_call = FunctionCall(
323
382
  {
@@ -325,7 +384,13 @@ def _parse_chat_history(
325
384
  "args": tool_call["args"],
326
385
  }
327
386
  )
328
- parts.append(Part(function_call=function_call))
387
+ ai_message_parts.append(Part(function_call=function_call))
388
+ tool_messages_parts = _get_ai_message_tool_messages_parts(
389
+ tool_messages=tool_messages, ai_message=message
390
+ )
391
+ messages.append(Content(role=role, parts=ai_message_parts))
392
+ messages.append(Content(role="user", parts=tool_messages_parts))
393
+ continue
329
394
  elif raw_function_call := message.additional_kwargs.get("function_call"):
330
395
  function_call = FunctionCall(
331
396
  {
@@ -344,60 +409,7 @@ def _parse_chat_history(
344
409
  system_instruction = None
345
410
  elif isinstance(message, FunctionMessage):
346
411
  role = "user"
347
- response: Any
348
- if not isinstance(message.content, str):
349
- response = message.content
350
- else:
351
- try:
352
- response = json.loads(message.content)
353
- except json.JSONDecodeError:
354
- response = message.content # leave as str representation
355
- parts = [
356
- Part(
357
- function_response=FunctionResponse(
358
- name=message.name,
359
- response=(
360
- {"output": response}
361
- if not isinstance(response, dict)
362
- else response
363
- ),
364
- )
365
- )
366
- ]
367
- elif isinstance(message, ToolMessage):
368
- role = "user"
369
- prev_message: Optional[BaseMessage] = (
370
- input_messages[i - 1] if i > 0 else None
371
- )
372
- if (
373
- prev_message
374
- and isinstance(prev_message, AIMessage)
375
- and prev_message.tool_calls
376
- ):
377
- # message.name can be null for ToolMessage
378
- name: str = prev_message.tool_calls[0]["name"]
379
- else:
380
- name = message.name # type: ignore
381
- tool_response: Any
382
- if not isinstance(message.content, str):
383
- tool_response = message.content
384
- else:
385
- try:
386
- tool_response = json.loads(message.content)
387
- except json.JSONDecodeError:
388
- tool_response = message.content # leave as str representation
389
- parts = [
390
- Part(
391
- function_response=FunctionResponse(
392
- name=name,
393
- response=(
394
- {"output": tool_response}
395
- if not isinstance(tool_response, dict)
396
- else tool_response
397
- ),
398
- )
399
- )
400
- ]
412
+ parts = [_convert_tool_message_to_part(message)]
401
413
  else:
402
414
  raise ValueError(
403
415
  f"Unexpected message with type {type(message)} at the position {i}."
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: langchain-google-genai
3
- Version: 2.0.8
3
+ Version: 2.0.10
4
4
  Summary: An integration package connecting Google's genai package and LangChain
5
5
  Home-page: https://github.com/langchain-ai/langchain-google
6
6
  License: MIT
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3.11
13
13
  Classifier: Programming Language :: Python :: 3.12
14
14
  Requires-Dist: filetype (>=1.2.0,<2.0.0)
15
15
  Requires-Dist: google-generativeai (>=0.8.0,<0.9.0)
16
- Requires-Dist: langchain-core (>=0.3.27,<0.4.0)
16
+ Requires-Dist: langchain-core (>=0.3.37,<0.4.0)
17
17
  Requires-Dist: pydantic (>=2,<3)
18
18
  Project-URL: Repository, https://github.com/langchain-ai/langchain-google
19
19
  Project-URL: Source Code, https://github.com/langchain-ai/langchain-google/tree/main/libs/genai
@@ -1,16 +1,16 @@
1
1
  langchain_google_genai/__init__.py,sha256=Oji-S2KYWrku1wyQEskY84IOfY8MfRhujjJ4d7hbsk4,2758
2
2
  langchain_google_genai/_common.py,sha256=ASlwE8hEbvOm55BVF_D4rf2nl7RYsnpsi5xbM6DW3Cc,1576
3
3
  langchain_google_genai/_enums.py,sha256=KLPmxS1K83K4HjBIXFaXoL_sFEOv8Hq-2B2PDMKyDgo,197
4
- langchain_google_genai/_function_utils.py,sha256=xcUwX2DmGM4UwH7bhBC6W9E5oVAE8k_l9lMYzJUJwA0,17433
4
+ langchain_google_genai/_function_utils.py,sha256=c0bYzUcWyDnaYQi5tPtBxl7KGV4FswzSb3ywu8tD6yI,18036
5
5
  langchain_google_genai/_genai_extension.py,sha256=81a4ly5ZHlqMf37uJfdB8K41qE6J5ujLnbUypIfFf2o,20775
6
6
  langchain_google_genai/_image_utils.py,sha256=tPrQyMvVmO8xkuow1SvA91omxUEv9ZUy1EMHNGjMAKY,5202
7
- langchain_google_genai/chat_models.py,sha256=OXm70GS_N6ror9A8imm6TIFVAfQ-DgdhIMbSZKExyVE,54450
7
+ langchain_google_genai/chat_models.py,sha256=F36_mMwLgnsQIEDJomKLuF4QdXdjkatXR5Ut-nMEvRA,55022
8
8
  langchain_google_genai/embeddings.py,sha256=jQRWPXD9twXoVBlXJQG7Duz0fb8UC0kgRzzwAmW3Dic,10146
9
9
  langchain_google_genai/genai_aqa.py,sha256=qB6h3-BSXqe0YLR3eeVllYzmNKK6ofI6xJLdBahUVZo,4300
10
10
  langchain_google_genai/google_vector_store.py,sha256=4wvhIiOmc3Fo046FyafPmT9NBCLek-9bgluvuTfrbpQ,16148
11
11
  langchain_google_genai/llms.py,sha256=EPUgkz5aqKOyKbztT7br8w60Uo5D_X_bF5qP-zd6iLs,14593
12
12
  langchain_google_genai/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
13
- langchain_google_genai-2.0.8.dist-info/LICENSE,sha256=DppmdYJVSc1jd0aio6ptnMUn5tIHrdAhQ12SclEBfBg,1072
14
- langchain_google_genai-2.0.8.dist-info/METADATA,sha256=HiODJnDpI3kyP8KioKDXiJItnXQsVc_AC-wamxdeyMY,3594
15
- langchain_google_genai-2.0.8.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
16
- langchain_google_genai-2.0.8.dist-info/RECORD,,
13
+ langchain_google_genai-2.0.10.dist-info/LICENSE,sha256=DppmdYJVSc1jd0aio6ptnMUn5tIHrdAhQ12SclEBfBg,1072
14
+ langchain_google_genai-2.0.10.dist-info/METADATA,sha256=2VjXxw5v4_8anWbUPouX2Y3yjG8JmBk9mKTJwIpvEkw,3595
15
+ langchain_google_genai-2.0.10.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
16
+ langchain_google_genai-2.0.10.dist-info/RECORD,,