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.
- langchain_google_genai/_function_utils.py +14 -3
- langchain_google_genai/chat_models.py +71 -59
- {langchain_google_genai-2.0.8.dist-info → langchain_google_genai-2.0.10.dist-info}/METADATA +2 -2
- {langchain_google_genai-2.0.8.dist-info → langchain_google_genai-2.0.10.dist-info}/RECORD +6 -6
- {langchain_google_genai-2.0.8.dist-info → langchain_google_genai-2.0.10.dist-info}/LICENSE +0 -0
- {langchain_google_genai-2.0.8.dist-info → langchain_google_genai-2.0.10.dist-info}/WHEEL +0 -0
|
@@ -235,13 +235,16 @@ def _format_base_tool_to_function_declaration(
|
|
|
235
235
|
),
|
|
236
236
|
)
|
|
237
237
|
|
|
238
|
-
if
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
314
|
-
|
|
315
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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=
|
|
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=
|
|
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.
|
|
14
|
-
langchain_google_genai-2.0.
|
|
15
|
-
langchain_google_genai-2.0.
|
|
16
|
-
langchain_google_genai-2.0.
|
|
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,,
|
|
File without changes
|
|
File without changes
|