langchain-google-genai 1.0.6__tar.gz → 1.0.7__tar.gz
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-1.0.6 → langchain_google_genai-1.0.7}/PKG-INFO +3 -3
- langchain_google_genai-1.0.7/langchain_google_genai/_function_utils.py +340 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/chat_models.py +43 -6
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/embeddings.py +2 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/llms.py +10 -3
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/pyproject.toml +5 -4
- langchain_google_genai-1.0.6/langchain_google_genai/_function_utils.py +0 -237
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/LICENSE +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/README.md +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/__init__.py +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/_common.py +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/_enums.py +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/_genai_extension.py +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/_image_utils.py +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/genai_aqa.py +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/google_vector_store.py +0 -0
- {langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/py.typed +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: langchain-google-genai
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.7
|
|
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
|
|
@@ -12,8 +12,8 @@ Classifier: Programming Language :: Python :: 3.10
|
|
|
12
12
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
13
|
Classifier: Programming Language :: Python :: 3.12
|
|
14
14
|
Provides-Extra: images
|
|
15
|
-
Requires-Dist: google-generativeai (>=0.
|
|
16
|
-
Requires-Dist: langchain-core (>=0.2.
|
|
15
|
+
Requires-Dist: google-generativeai (>=0.7.0,<0.8.0)
|
|
16
|
+
Requires-Dist: langchain-core (>=0.2.9,<0.3)
|
|
17
17
|
Requires-Dist: pillow (>=10.1.0,<11.0.0) ; extra == "images"
|
|
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
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import (
|
|
4
|
+
Any,
|
|
5
|
+
Callable,
|
|
6
|
+
Collection,
|
|
7
|
+
Dict,
|
|
8
|
+
List,
|
|
9
|
+
Literal,
|
|
10
|
+
Optional,
|
|
11
|
+
Sequence,
|
|
12
|
+
Type,
|
|
13
|
+
TypedDict,
|
|
14
|
+
Union,
|
|
15
|
+
cast,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
import google.ai.generativelanguage as glm
|
|
19
|
+
from google.ai.generativelanguage import FunctionCallingConfig, FunctionDeclaration
|
|
20
|
+
from google.ai.generativelanguage import Tool as GoogleTool
|
|
21
|
+
from google.generativeai.types.content_types import ToolDict # type: ignore[import]
|
|
22
|
+
from langchain_core.pydantic_v1 import BaseModel
|
|
23
|
+
from langchain_core.tools import BaseTool
|
|
24
|
+
from langchain_core.tools import tool as callable_as_lc_tool
|
|
25
|
+
from langchain_core.utils.json_schema import dereference_refs
|
|
26
|
+
|
|
27
|
+
TYPE_ENUM = {
|
|
28
|
+
"string": glm.Type.STRING,
|
|
29
|
+
"number": glm.Type.NUMBER,
|
|
30
|
+
"integer": glm.Type.INTEGER,
|
|
31
|
+
"boolean": glm.Type.BOOLEAN,
|
|
32
|
+
"array": glm.Type.ARRAY,
|
|
33
|
+
"object": glm.Type.OBJECT,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
TYPE_ENUM_REVERSE = {v: k for k, v in TYPE_ENUM.items()}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class _ToolDictLike(TypedDict):
|
|
40
|
+
function_declarations: _FunctionDeclarationLikeList
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class _FunctionDeclarationDict(TypedDict):
|
|
44
|
+
name: str
|
|
45
|
+
description: str
|
|
46
|
+
parameters: Dict[str, Collection[str]]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class _ToolDict(TypedDict):
|
|
50
|
+
function_declarations: Sequence[_FunctionDeclarationDict]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Info: This is a FunctionDeclaration(=fc).
|
|
54
|
+
_FunctionDeclarationLike = Union[
|
|
55
|
+
BaseTool, Type[BaseModel], FunctionDeclaration, Callable, Dict[str, Any]
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
# Info: This mean one tool.
|
|
59
|
+
_FunctionDeclarationLikeList = Sequence[_FunctionDeclarationLike]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
# Info: This means one tool=Sequence of FunctionDeclaration
|
|
63
|
+
# The dict should be GoogleTool like. {"function_declarations": [ { "name": ...}.
|
|
64
|
+
# OpenAI like dict is not be accepted. {{'type': 'function', 'function': {'name': ...}
|
|
65
|
+
_ToolsType = Union[
|
|
66
|
+
GoogleTool,
|
|
67
|
+
ToolDict,
|
|
68
|
+
_ToolDictLike,
|
|
69
|
+
_FunctionDeclarationLikeList,
|
|
70
|
+
_FunctionDeclarationLike,
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
#
|
|
75
|
+
# Info: GoogleTool means function_declarations and proto.Message.
|
|
76
|
+
def convert_to_genai_function_declarations(
|
|
77
|
+
tool: _ToolsType,
|
|
78
|
+
) -> GoogleTool:
|
|
79
|
+
if isinstance(tool, list):
|
|
80
|
+
# multiple _FunctionDeclarationLike
|
|
81
|
+
return GoogleTool(
|
|
82
|
+
function_declarations=_convert_fc_likes_to_genai_function(tool)
|
|
83
|
+
)
|
|
84
|
+
elif isinstance(tool, (BaseTool, FunctionDeclaration)):
|
|
85
|
+
# single _FunctionDeclarationLike
|
|
86
|
+
return GoogleTool(
|
|
87
|
+
function_declarations=[_convert_fc_like_to_genai_function(tool)]
|
|
88
|
+
)
|
|
89
|
+
elif isinstance(tool, type) and issubclass(tool, BaseModel):
|
|
90
|
+
# single _FunctionDeclarationLike
|
|
91
|
+
return GoogleTool(
|
|
92
|
+
function_declarations=[_convert_fc_like_to_genai_function(tool)]
|
|
93
|
+
)
|
|
94
|
+
elif isinstance(tool, GoogleTool):
|
|
95
|
+
return cast(GoogleTool, tool)
|
|
96
|
+
elif callable(tool):
|
|
97
|
+
return GoogleTool(
|
|
98
|
+
function_declarations=[
|
|
99
|
+
_convert_tool_to_genai_function(callable_as_lc_tool()(tool))
|
|
100
|
+
]
|
|
101
|
+
)
|
|
102
|
+
elif isinstance(tool, dict):
|
|
103
|
+
return GoogleTool(function_declarations=_convert_dict_to_genai_functions(tool)) # type: ignore
|
|
104
|
+
else:
|
|
105
|
+
raise ValueError(f"Unsupported tool type {tool}")
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def tool_to_dict(tool: GoogleTool) -> _ToolDict:
|
|
109
|
+
function_declarations = []
|
|
110
|
+
for function_declaration_proto in tool.function_declarations:
|
|
111
|
+
properties: Dict[str, Any] = {}
|
|
112
|
+
for property in function_declaration_proto.parameters.properties:
|
|
113
|
+
property_type = function_declaration_proto.parameters.properties[
|
|
114
|
+
property
|
|
115
|
+
].type
|
|
116
|
+
property_dict = {"type": TYPE_ENUM_REVERSE[property_type]}
|
|
117
|
+
property_description = function_declaration_proto.parameters.properties[
|
|
118
|
+
property
|
|
119
|
+
].description
|
|
120
|
+
if property_description:
|
|
121
|
+
property_dict["description"] = property_description
|
|
122
|
+
properties[property] = property_dict
|
|
123
|
+
name = function_declaration_proto.name
|
|
124
|
+
description = function_declaration_proto.description
|
|
125
|
+
parameters = {"type": "object", "properties": properties}
|
|
126
|
+
if function_declaration_proto.parameters.required:
|
|
127
|
+
parameters["required"] = function_declaration_proto.parameters.required
|
|
128
|
+
function_declaration = _FunctionDeclarationDict(
|
|
129
|
+
name=name, description=description, parameters=parameters
|
|
130
|
+
)
|
|
131
|
+
function_declarations.append(function_declaration)
|
|
132
|
+
return {"function_declarations": function_declarations}
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _convert_fc_likes_to_genai_function(
|
|
136
|
+
fc_likes: _FunctionDeclarationLikeList,
|
|
137
|
+
) -> Sequence[FunctionDeclaration]:
|
|
138
|
+
if isinstance(fc_likes, list):
|
|
139
|
+
return [_convert_fc_like_to_genai_function(fc) for fc in fc_likes]
|
|
140
|
+
raise ValueError(f"Unsupported fc_likes type {fc_likes}")
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _convert_fc_like_to_genai_function(
|
|
144
|
+
fc_like: _FunctionDeclarationLike,
|
|
145
|
+
) -> FunctionDeclaration:
|
|
146
|
+
if isinstance(fc_like, BaseTool):
|
|
147
|
+
return _convert_tool_to_genai_function(fc_like)
|
|
148
|
+
elif isinstance(fc_like, type) and issubclass(fc_like, BaseModel):
|
|
149
|
+
return _convert_pydantic_to_genai_function(fc_like)
|
|
150
|
+
elif isinstance(fc_like, dict):
|
|
151
|
+
# TODO: add declaration_index
|
|
152
|
+
return _convert_dict_to_genai_function(fc_like)
|
|
153
|
+
elif callable(fc_like):
|
|
154
|
+
return _convert_tool_to_genai_function(callable_as_lc_tool()(fc_like))
|
|
155
|
+
else:
|
|
156
|
+
raise ValueError(f"Unsupported fc_like type {fc_like}")
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def _convert_tool_dict_to_genai_functions(
|
|
160
|
+
tool_dict: _ToolDictLike,
|
|
161
|
+
) -> Sequence[FunctionDeclaration]:
|
|
162
|
+
if "function_declarations" in tool_dict:
|
|
163
|
+
return _convert_dicts_to_genai_functions(tool_dict["function_declarations"]) # type: ignore
|
|
164
|
+
else:
|
|
165
|
+
raise ValueError(f"Unsupported function tool_dict type {tool_dict}")
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _convert_dict_to_genai_functions(
|
|
169
|
+
function_declarations_dict: Dict[str, Any],
|
|
170
|
+
) -> Sequence[FunctionDeclaration]:
|
|
171
|
+
if "function_declarations" in function_declarations_dict:
|
|
172
|
+
# GoogleTool like
|
|
173
|
+
return [
|
|
174
|
+
_convert_dict_to_genai_function(fc, i)
|
|
175
|
+
for i, fc in enumerate(function_declarations_dict["function_declarations"])
|
|
176
|
+
]
|
|
177
|
+
d = function_declarations_dict
|
|
178
|
+
if "name" in d and "description" in d and "parameters" in d:
|
|
179
|
+
# _FunctionDeclarationDict
|
|
180
|
+
return [_convert_dict_to_genai_function(d)]
|
|
181
|
+
else:
|
|
182
|
+
# OpenAI like?
|
|
183
|
+
raise ValueError(f"Unsupported function call type {function_declarations_dict}")
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
def _convert_dicts_to_genai_functions(
|
|
187
|
+
function_declaration_dicts: Sequence[Dict[str, Any]],
|
|
188
|
+
) -> Sequence[FunctionDeclaration]:
|
|
189
|
+
return [
|
|
190
|
+
_convert_dict_to_genai_function(function_declaration_dict, i)
|
|
191
|
+
for i, function_declaration_dict in enumerate(function_declaration_dicts)
|
|
192
|
+
]
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _convert_dict_to_genai_function(
|
|
196
|
+
function_declaration_dict: Dict[str, Any], declaration_index: int = 0
|
|
197
|
+
) -> FunctionDeclaration:
|
|
198
|
+
formatted_fc = {
|
|
199
|
+
"name": function_declaration_dict.get("name", f"unknown-{declaration_index}"),
|
|
200
|
+
"description": function_declaration_dict.get("description", "no-description"),
|
|
201
|
+
}
|
|
202
|
+
if "parameters" in function_declaration_dict:
|
|
203
|
+
formatted_fc["parameters"] = {
|
|
204
|
+
"properties": {
|
|
205
|
+
k: {
|
|
206
|
+
"type_": TYPE_ENUM[v["type"]],
|
|
207
|
+
"description": v.get("description"),
|
|
208
|
+
}
|
|
209
|
+
for k, v in function_declaration_dict["parameters"][
|
|
210
|
+
"properties"
|
|
211
|
+
].items()
|
|
212
|
+
},
|
|
213
|
+
"required": function_declaration_dict.get("parameters", []).get(
|
|
214
|
+
"required", []
|
|
215
|
+
),
|
|
216
|
+
"type_": TYPE_ENUM[function_declaration_dict["parameters"]["type"]],
|
|
217
|
+
}
|
|
218
|
+
return FunctionDeclaration(**formatted_fc)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def _convert_tool_to_genai_function(tool: BaseTool) -> FunctionDeclaration:
|
|
222
|
+
if tool.args_schema:
|
|
223
|
+
fc = tool.args_schema
|
|
224
|
+
if isinstance(fc, type) and issubclass(fc, BaseModel):
|
|
225
|
+
return _convert_pydantic_to_genai_function(
|
|
226
|
+
fc, tool_name=tool.name, tool_description=tool.description
|
|
227
|
+
)
|
|
228
|
+
raise ValueError(f"Unsupported function call type {fc}")
|
|
229
|
+
else:
|
|
230
|
+
return FunctionDeclaration(
|
|
231
|
+
name=tool.name,
|
|
232
|
+
description=tool.description,
|
|
233
|
+
parameters={
|
|
234
|
+
"properties": {
|
|
235
|
+
"__arg1": {"type_": TYPE_ENUM["string"]},
|
|
236
|
+
},
|
|
237
|
+
"required": ["__arg1"],
|
|
238
|
+
"type_": TYPE_ENUM["object"],
|
|
239
|
+
},
|
|
240
|
+
)
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
def _convert_pydantic_to_genai_function(
|
|
244
|
+
pydantic_model: Type[BaseModel],
|
|
245
|
+
tool_name: Optional[str] = None,
|
|
246
|
+
tool_description: Optional[str] = None,
|
|
247
|
+
) -> FunctionDeclaration:
|
|
248
|
+
schema = dereference_refs(pydantic_model.schema())
|
|
249
|
+
schema.pop("definitions", None)
|
|
250
|
+
function_declaration = FunctionDeclaration(
|
|
251
|
+
name=tool_name if tool_name else schema.get("title"),
|
|
252
|
+
description=tool_description if tool_description else schema.get("description"),
|
|
253
|
+
parameters={
|
|
254
|
+
"properties": {
|
|
255
|
+
k: {
|
|
256
|
+
"type_": _get_type_from_schema(v),
|
|
257
|
+
"description": v.get("description"),
|
|
258
|
+
}
|
|
259
|
+
for k, v in schema["properties"].items()
|
|
260
|
+
},
|
|
261
|
+
"required": schema.get("required", []),
|
|
262
|
+
"type_": TYPE_ENUM[schema["type"]],
|
|
263
|
+
},
|
|
264
|
+
)
|
|
265
|
+
return function_declaration
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
def _get_type_from_schema(schema: Dict[str, Any]) -> int:
|
|
269
|
+
if "anyOf" in schema:
|
|
270
|
+
types = [_get_type_from_schema(sub_schema) for sub_schema in schema["anyOf"]]
|
|
271
|
+
types = [t for t in types if t is not None] # Remove None values
|
|
272
|
+
if types:
|
|
273
|
+
return types[-1] # TODO: update FunctionDeclaration and pass all types?
|
|
274
|
+
else:
|
|
275
|
+
pass
|
|
276
|
+
elif "type" in schema:
|
|
277
|
+
stype = str(schema["type"])
|
|
278
|
+
if stype in TYPE_ENUM:
|
|
279
|
+
return TYPE_ENUM[stype]
|
|
280
|
+
else:
|
|
281
|
+
pass
|
|
282
|
+
else:
|
|
283
|
+
pass
|
|
284
|
+
return TYPE_ENUM["string"] # Default to string if no valid types found
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
_ToolChoiceType = Union[
|
|
288
|
+
dict, List[str], str, Literal["auto", "none", "any"], Literal[True]
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
class _FunctionCallingConfigDict(TypedDict):
|
|
293
|
+
mode: Union[FunctionCallingConfig.Mode, str]
|
|
294
|
+
allowed_function_names: Optional[List[str]]
|
|
295
|
+
|
|
296
|
+
|
|
297
|
+
class _ToolConfigDict(TypedDict):
|
|
298
|
+
function_calling_config: _FunctionCallingConfigDict
|
|
299
|
+
|
|
300
|
+
|
|
301
|
+
def _tool_choice_to_tool_config(
|
|
302
|
+
tool_choice: _ToolChoiceType,
|
|
303
|
+
all_names: List[str],
|
|
304
|
+
) -> _ToolConfigDict:
|
|
305
|
+
allowed_function_names: Optional[List[str]] = None
|
|
306
|
+
if tool_choice is True or tool_choice == "any":
|
|
307
|
+
mode = "any"
|
|
308
|
+
allowed_function_names = all_names
|
|
309
|
+
elif tool_choice == "auto":
|
|
310
|
+
mode = "auto"
|
|
311
|
+
elif tool_choice == "none":
|
|
312
|
+
mode = "none"
|
|
313
|
+
elif isinstance(tool_choice, str):
|
|
314
|
+
mode = "any"
|
|
315
|
+
allowed_function_names = [tool_choice]
|
|
316
|
+
elif isinstance(tool_choice, list):
|
|
317
|
+
mode = "any"
|
|
318
|
+
allowed_function_names = tool_choice
|
|
319
|
+
elif isinstance(tool_choice, dict):
|
|
320
|
+
if "mode" in tool_choice:
|
|
321
|
+
mode = tool_choice["mode"]
|
|
322
|
+
allowed_function_names = tool_choice.get("allowed_function_names")
|
|
323
|
+
elif "function_calling_config" in tool_choice:
|
|
324
|
+
mode = tool_choice["function_calling_config"]["mode"]
|
|
325
|
+
allowed_function_names = tool_choice["function_calling_config"].get(
|
|
326
|
+
"allowed_function_names"
|
|
327
|
+
)
|
|
328
|
+
else:
|
|
329
|
+
raise ValueError(
|
|
330
|
+
f"Unrecognized tool choice format:\n\n{tool_choice=}\n\nShould match "
|
|
331
|
+
f"Google GenerativeAI ToolConfig or FunctionCallingConfig format."
|
|
332
|
+
)
|
|
333
|
+
else:
|
|
334
|
+
raise ValueError(f"Unrecognized tool choice format:\n\n{tool_choice=}")
|
|
335
|
+
return _ToolConfigDict(
|
|
336
|
+
function_calling_config={
|
|
337
|
+
"mode": mode,
|
|
338
|
+
"allowed_function_names": allowed_function_names,
|
|
339
|
+
}
|
|
340
|
+
)
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/chat_models.py
RENAMED
|
@@ -8,6 +8,7 @@ import os
|
|
|
8
8
|
import uuid
|
|
9
9
|
import warnings
|
|
10
10
|
from io import BytesIO
|
|
11
|
+
from operator import itemgetter
|
|
11
12
|
from typing import (
|
|
12
13
|
Any,
|
|
13
14
|
AsyncIterator,
|
|
@@ -19,6 +20,7 @@ from typing import (
|
|
|
19
20
|
Optional,
|
|
20
21
|
Sequence,
|
|
21
22
|
Tuple,
|
|
23
|
+
Type,
|
|
22
24
|
Union,
|
|
23
25
|
cast,
|
|
24
26
|
)
|
|
@@ -65,10 +67,15 @@ from langchain_core.messages import (
|
|
|
65
67
|
ToolMessage,
|
|
66
68
|
)
|
|
67
69
|
from langchain_core.messages.ai import UsageMetadata
|
|
68
|
-
from langchain_core.output_parsers.
|
|
70
|
+
from langchain_core.output_parsers.base import OutputParserLike
|
|
71
|
+
from langchain_core.output_parsers.openai_tools import (
|
|
72
|
+
JsonOutputToolsParser,
|
|
73
|
+
PydanticToolsParser,
|
|
74
|
+
parse_tool_calls,
|
|
75
|
+
)
|
|
69
76
|
from langchain_core.outputs import ChatGeneration, ChatGenerationChunk, ChatResult
|
|
70
|
-
from langchain_core.pydantic_v1 import Field, SecretStr, root_validator
|
|
71
|
-
from langchain_core.runnables import Runnable
|
|
77
|
+
from langchain_core.pydantic_v1 import BaseModel, Field, SecretStr, root_validator
|
|
78
|
+
from langchain_core.runnables import Runnable, RunnablePassthrough
|
|
72
79
|
from langchain_core.utils import get_from_dict_or_env
|
|
73
80
|
from tenacity import (
|
|
74
81
|
before_sleep_log,
|
|
@@ -612,8 +619,8 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
612
619
|
|
|
613
620
|
convert_system_message_to_human: bool = False
|
|
614
621
|
"""Whether to merge any leading SystemMessage into the following HumanMessage.
|
|
615
|
-
|
|
616
|
-
Gemini does not support system messages; any unsupported messages will
|
|
622
|
+
|
|
623
|
+
Gemini does not support system messages; any unsupported messages will
|
|
617
624
|
raise an error."""
|
|
618
625
|
|
|
619
626
|
class Config:
|
|
@@ -937,6 +944,33 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
937
944
|
)
|
|
938
945
|
return result.total_tokens
|
|
939
946
|
|
|
947
|
+
def with_structured_output(
|
|
948
|
+
self,
|
|
949
|
+
schema: Union[Dict, Type[BaseModel]],
|
|
950
|
+
*,
|
|
951
|
+
include_raw: bool = False,
|
|
952
|
+
**kwargs: Any,
|
|
953
|
+
) -> Runnable[LanguageModelInput, Union[Dict, BaseModel]]:
|
|
954
|
+
if kwargs:
|
|
955
|
+
raise ValueError(f"Received unsupported arguments {kwargs}")
|
|
956
|
+
if isinstance(schema, type) and issubclass(schema, BaseModel):
|
|
957
|
+
parser: OutputParserLike = PydanticToolsParser(
|
|
958
|
+
tools=[schema], first_tool_only=True
|
|
959
|
+
)
|
|
960
|
+
else:
|
|
961
|
+
parser = JsonOutputToolsParser()
|
|
962
|
+
llm = self.bind_tools([schema], tool_choice=False)
|
|
963
|
+
if include_raw:
|
|
964
|
+
parser_with_fallback = RunnablePassthrough.assign(
|
|
965
|
+
parsed=itemgetter("raw") | parser, parsing_error=lambda _: None
|
|
966
|
+
).with_fallbacks(
|
|
967
|
+
[RunnablePassthrough.assign(parsed=lambda _: None)],
|
|
968
|
+
exception_key="parsing_error",
|
|
969
|
+
)
|
|
970
|
+
return {"raw": llm} | parser_with_fallback
|
|
971
|
+
else:
|
|
972
|
+
return llm | parser
|
|
973
|
+
|
|
940
974
|
def bind_tools(
|
|
941
975
|
self,
|
|
942
976
|
tools: Sequence[Union[ToolDict, GoogleTool]],
|
|
@@ -963,7 +997,9 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
963
997
|
f"both:\n\n{tool_choice=}\n\n{tool_config=}"
|
|
964
998
|
)
|
|
965
999
|
# Bind dicts for easier serialization/deserialization.
|
|
966
|
-
genai_tools = [
|
|
1000
|
+
genai_tools = [
|
|
1001
|
+
tool_to_dict(convert_to_genai_function_declarations(tool)) for tool in tools
|
|
1002
|
+
]
|
|
967
1003
|
if tool_choice:
|
|
968
1004
|
all_names = [
|
|
969
1005
|
f["name"] # type: ignore[index]
|
|
@@ -971,4 +1007,5 @@ class ChatGoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseChatModel):
|
|
|
971
1007
|
for f in t["function_declarations"]
|
|
972
1008
|
]
|
|
973
1009
|
tool_config = _tool_choice_to_tool_config(tool_choice, all_names)
|
|
1010
|
+
|
|
974
1011
|
return self.bind(tools=genai_tools, tool_config=tool_config, **kwargs)
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/embeddings.py
RENAMED
|
@@ -86,6 +86,8 @@ class GoogleGenerativeAIEmbeddings(BaseModel, Embeddings):
|
|
|
86
86
|
google_api_key = get_from_dict_or_env(
|
|
87
87
|
values, "google_api_key", "GOOGLE_API_KEY"
|
|
88
88
|
)
|
|
89
|
+
if isinstance(google_api_key, SecretStr):
|
|
90
|
+
google_api_key = google_api_key.get_secret_value()
|
|
89
91
|
client_info = get_client_info("GoogleGenerativeAIEmbeddings")
|
|
90
92
|
|
|
91
93
|
values["client"] = build_generative_service(
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/llms.py
RENAMED
|
@@ -325,9 +325,16 @@ class GoogleGenerativeAI(_BaseGoogleGenerativeAI, BaseLLM):
|
|
|
325
325
|
run_manager: Optional[CallbackManagerForLLMRun] = None,
|
|
326
326
|
**kwargs: Any,
|
|
327
327
|
) -> Iterator[GenerationChunk]:
|
|
328
|
-
generation_config =
|
|
329
|
-
|
|
330
|
-
|
|
328
|
+
generation_config = {
|
|
329
|
+
"stop_sequences": stop,
|
|
330
|
+
"temperature": self.temperature,
|
|
331
|
+
"top_p": self.top_p,
|
|
332
|
+
"top_k": self.top_k,
|
|
333
|
+
"max_output_tokens": self.max_output_tokens,
|
|
334
|
+
"candidate_count": self.n,
|
|
335
|
+
}
|
|
336
|
+
generation_config = generation_config | kwargs.get("generation_config", {})
|
|
337
|
+
|
|
331
338
|
for stream_resp in _completion_with_retry(
|
|
332
339
|
self,
|
|
333
340
|
prompt,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[tool.poetry]
|
|
2
2
|
name = "langchain-google-genai"
|
|
3
|
-
version = "1.0.
|
|
3
|
+
version = "1.0.7"
|
|
4
4
|
description = "An integration package connecting Google's genai package and LangChain"
|
|
5
5
|
authors = []
|
|
6
6
|
readme = "README.md"
|
|
@@ -12,8 +12,8 @@ license = "MIT"
|
|
|
12
12
|
|
|
13
13
|
[tool.poetry.dependencies]
|
|
14
14
|
python = ">=3.9,<4.0"
|
|
15
|
-
langchain-core = ">=0.2.
|
|
16
|
-
google-generativeai = "^0.
|
|
15
|
+
langchain-core = ">=0.2.9,<0.3"
|
|
16
|
+
google-generativeai = "^0.7.0"
|
|
17
17
|
pillow = { version = "^10.1.0", optional = true }
|
|
18
18
|
|
|
19
19
|
[tool.poetry.extras]
|
|
@@ -61,6 +61,7 @@ types-google-cloud-ndb = "^2.2.0.1"
|
|
|
61
61
|
types-pillow = "^10.1.0.2"
|
|
62
62
|
types-protobuf = "^4.24.0.20240302"
|
|
63
63
|
langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" }
|
|
64
|
+
numpy = "^1.26.2"
|
|
64
65
|
|
|
65
66
|
[tool.poetry.group.dev]
|
|
66
67
|
optional = true
|
|
@@ -72,7 +73,7 @@ types-pillow = "^10.1.0.2"
|
|
|
72
73
|
types-google-cloud-ndb = "^2.2.0.1"
|
|
73
74
|
langchain-core = { git = "https://github.com/langchain-ai/langchain.git", subdirectory = "libs/core" }
|
|
74
75
|
|
|
75
|
-
[tool.ruff]
|
|
76
|
+
[tool.ruff.lint]
|
|
76
77
|
select = [
|
|
77
78
|
"E", # pycodestyle
|
|
78
79
|
"F", # pyflakes
|
|
@@ -1,237 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
from typing import (
|
|
4
|
-
Any,
|
|
5
|
-
Callable,
|
|
6
|
-
Dict,
|
|
7
|
-
List,
|
|
8
|
-
Literal,
|
|
9
|
-
Optional,
|
|
10
|
-
Sequence,
|
|
11
|
-
Type,
|
|
12
|
-
TypedDict,
|
|
13
|
-
Union,
|
|
14
|
-
cast,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
|
-
import google.ai.generativelanguage as glm
|
|
18
|
-
from google.ai.generativelanguage import (
|
|
19
|
-
FunctionCallingConfig,
|
|
20
|
-
FunctionDeclaration,
|
|
21
|
-
)
|
|
22
|
-
from google.ai.generativelanguage import (
|
|
23
|
-
Tool as GoogleTool,
|
|
24
|
-
)
|
|
25
|
-
from langchain_core.pydantic_v1 import BaseModel
|
|
26
|
-
from langchain_core.tools import BaseTool
|
|
27
|
-
from langchain_core.tools import tool as callable_as_lc_tool
|
|
28
|
-
from langchain_core.utils.json_schema import dereference_refs
|
|
29
|
-
|
|
30
|
-
TYPE_ENUM = {
|
|
31
|
-
"string": glm.Type.STRING,
|
|
32
|
-
"number": glm.Type.NUMBER,
|
|
33
|
-
"integer": glm.Type.INTEGER,
|
|
34
|
-
"boolean": glm.Type.BOOLEAN,
|
|
35
|
-
"array": glm.Type.ARRAY,
|
|
36
|
-
"object": glm.Type.OBJECT,
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
TYPE_ENUM_REVERSE = {v: k for k, v in TYPE_ENUM.items()}
|
|
40
|
-
|
|
41
|
-
_FunctionDeclarationLike = Union[
|
|
42
|
-
BaseTool, Type[BaseModel], dict, Callable, FunctionDeclaration
|
|
43
|
-
]
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class _ToolDict(TypedDict):
|
|
47
|
-
function_declarations: Sequence[_FunctionDeclarationLike]
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
def convert_to_genai_function_declarations(
|
|
51
|
-
tool: Union[
|
|
52
|
-
GoogleTool,
|
|
53
|
-
_ToolDict,
|
|
54
|
-
_FunctionDeclarationLike,
|
|
55
|
-
Sequence[_FunctionDeclarationLike],
|
|
56
|
-
],
|
|
57
|
-
) -> GoogleTool:
|
|
58
|
-
if isinstance(tool, GoogleTool):
|
|
59
|
-
return cast(GoogleTool, tool)
|
|
60
|
-
if isinstance(tool, type) and issubclass(tool, BaseModel):
|
|
61
|
-
return GoogleTool(function_declarations=[_convert_to_genai_function(tool)])
|
|
62
|
-
if callable(tool):
|
|
63
|
-
return _convert_tool_to_genai_function(callable_as_lc_tool()(tool))
|
|
64
|
-
if isinstance(tool, list):
|
|
65
|
-
return convert_to_genai_function_declarations({"function_declarations": tool})
|
|
66
|
-
if isinstance(tool, dict) and "function_declarations" in tool:
|
|
67
|
-
return GoogleTool(
|
|
68
|
-
function_declarations=[
|
|
69
|
-
_convert_to_genai_function(fc) for fc in tool["function_declarations"]
|
|
70
|
-
],
|
|
71
|
-
)
|
|
72
|
-
return GoogleTool(function_declarations=[_convert_to_genai_function(tool)]) # type: ignore[arg-type]
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
def tool_to_dict(tool: GoogleTool) -> _ToolDict:
|
|
76
|
-
function_declarations = []
|
|
77
|
-
for function_declaration_proto in tool.function_declarations:
|
|
78
|
-
properties: Dict[str, Any] = {}
|
|
79
|
-
for property in function_declaration_proto.parameters.properties:
|
|
80
|
-
property_type = function_declaration_proto.parameters.properties[
|
|
81
|
-
property
|
|
82
|
-
].type
|
|
83
|
-
property_dict = {"type": TYPE_ENUM_REVERSE[property_type]}
|
|
84
|
-
property_description = function_declaration_proto.parameters.properties[
|
|
85
|
-
property
|
|
86
|
-
].description
|
|
87
|
-
if property_description:
|
|
88
|
-
property_dict["description"] = property_description
|
|
89
|
-
properties[property] = property_dict
|
|
90
|
-
function_declaration = {
|
|
91
|
-
"name": function_declaration_proto.name,
|
|
92
|
-
"description": function_declaration_proto.description,
|
|
93
|
-
"parameters": {"type": "object", "properties": properties},
|
|
94
|
-
}
|
|
95
|
-
if function_declaration_proto.parameters.required:
|
|
96
|
-
function_declaration["parameters"][ # type: ignore[index]
|
|
97
|
-
"required"
|
|
98
|
-
] = function_declaration_proto.parameters.required
|
|
99
|
-
function_declarations.append(function_declaration)
|
|
100
|
-
return {"function_declarations": function_declarations}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
def _convert_to_genai_function(fc: _FunctionDeclarationLike) -> FunctionDeclaration:
|
|
104
|
-
if isinstance(fc, BaseTool):
|
|
105
|
-
return _convert_tool_to_genai_function(fc)
|
|
106
|
-
elif isinstance(fc, type) and issubclass(fc, BaseModel):
|
|
107
|
-
return _convert_pydantic_to_genai_function(fc)
|
|
108
|
-
elif callable(fc):
|
|
109
|
-
return _convert_tool_to_genai_function(callable_as_lc_tool()(fc))
|
|
110
|
-
elif isinstance(fc, dict):
|
|
111
|
-
formatted_fc = {"name": fc["name"], "description": fc.get("description")}
|
|
112
|
-
if "parameters" in fc:
|
|
113
|
-
formatted_fc["parameters"] = {
|
|
114
|
-
"properties": {
|
|
115
|
-
k: {
|
|
116
|
-
"type_": TYPE_ENUM[v["type"]],
|
|
117
|
-
"description": v.get("description"),
|
|
118
|
-
}
|
|
119
|
-
for k, v in fc["parameters"]["properties"].items()
|
|
120
|
-
},
|
|
121
|
-
"required": fc.get("parameters", []).get("required", []),
|
|
122
|
-
"type_": TYPE_ENUM[fc["parameters"]["type"]],
|
|
123
|
-
}
|
|
124
|
-
return FunctionDeclaration(**formatted_fc)
|
|
125
|
-
else:
|
|
126
|
-
raise ValueError(f"Unsupported function call type {fc}")
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
def _convert_tool_to_genai_function(tool: BaseTool) -> FunctionDeclaration:
|
|
130
|
-
if tool.args_schema:
|
|
131
|
-
schema = dereference_refs(tool.args_schema.schema())
|
|
132
|
-
schema.pop("definitions", None)
|
|
133
|
-
return FunctionDeclaration(
|
|
134
|
-
name=tool.name or schema["title"],
|
|
135
|
-
description=tool.description or schema["description"],
|
|
136
|
-
parameters={
|
|
137
|
-
"properties": {
|
|
138
|
-
k: {
|
|
139
|
-
"type_": TYPE_ENUM[v["type"]],
|
|
140
|
-
"description": v.get("description"),
|
|
141
|
-
}
|
|
142
|
-
for k, v in schema["properties"].items()
|
|
143
|
-
},
|
|
144
|
-
"required": schema.get("required", []),
|
|
145
|
-
"type_": TYPE_ENUM[schema["type"]],
|
|
146
|
-
},
|
|
147
|
-
)
|
|
148
|
-
else:
|
|
149
|
-
return FunctionDeclaration(
|
|
150
|
-
name=tool.name,
|
|
151
|
-
description=tool.description,
|
|
152
|
-
parameters={
|
|
153
|
-
"properties": {
|
|
154
|
-
"__arg1": {"type_": TYPE_ENUM["string"]},
|
|
155
|
-
},
|
|
156
|
-
"required": ["__arg1"],
|
|
157
|
-
"type_": TYPE_ENUM["object"],
|
|
158
|
-
},
|
|
159
|
-
)
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
def _convert_pydantic_to_genai_function(
|
|
163
|
-
pydantic_model: Type[BaseModel],
|
|
164
|
-
) -> FunctionDeclaration:
|
|
165
|
-
schema = dereference_refs(pydantic_model.schema())
|
|
166
|
-
schema.pop("definitions", None)
|
|
167
|
-
return FunctionDeclaration(
|
|
168
|
-
name=schema["title"],
|
|
169
|
-
description=schema.get("description", ""),
|
|
170
|
-
parameters={
|
|
171
|
-
"properties": {
|
|
172
|
-
k: {
|
|
173
|
-
"type_": TYPE_ENUM[v["type"]],
|
|
174
|
-
"description": v.get("description"),
|
|
175
|
-
}
|
|
176
|
-
for k, v in schema["properties"].items()
|
|
177
|
-
},
|
|
178
|
-
"required": schema["required"],
|
|
179
|
-
"type_": TYPE_ENUM[schema["type"]],
|
|
180
|
-
},
|
|
181
|
-
)
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
_ToolChoiceType = Union[
|
|
185
|
-
dict, List[str], str, Literal["auto", "none", "any"], Literal[True]
|
|
186
|
-
]
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
class _FunctionCallingConfigDict(TypedDict):
|
|
190
|
-
mode: Union[FunctionCallingConfig.Mode, str]
|
|
191
|
-
allowed_function_names: Optional[List[str]]
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
class _ToolConfigDict(TypedDict):
|
|
195
|
-
function_calling_config: _FunctionCallingConfigDict
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
def _tool_choice_to_tool_config(
|
|
199
|
-
tool_choice: _ToolChoiceType,
|
|
200
|
-
all_names: List[str],
|
|
201
|
-
) -> _ToolConfigDict:
|
|
202
|
-
allowed_function_names: Optional[List[str]] = None
|
|
203
|
-
if tool_choice is True or tool_choice == "any":
|
|
204
|
-
mode = "any"
|
|
205
|
-
allowed_function_names = all_names
|
|
206
|
-
elif tool_choice == "auto":
|
|
207
|
-
mode = "auto"
|
|
208
|
-
elif tool_choice == "none":
|
|
209
|
-
mode = "none"
|
|
210
|
-
elif isinstance(tool_choice, str):
|
|
211
|
-
mode = "any"
|
|
212
|
-
allowed_function_names = [tool_choice]
|
|
213
|
-
elif isinstance(tool_choice, list):
|
|
214
|
-
mode = "any"
|
|
215
|
-
allowed_function_names = tool_choice
|
|
216
|
-
elif isinstance(tool_choice, dict):
|
|
217
|
-
if "mode" in tool_choice:
|
|
218
|
-
mode = tool_choice["mode"]
|
|
219
|
-
allowed_function_names = tool_choice.get("allowed_function_names")
|
|
220
|
-
elif "function_calling_config" in tool_choice:
|
|
221
|
-
mode = tool_choice["function_calling_config"]["mode"]
|
|
222
|
-
allowed_function_names = tool_choice["function_calling_config"].get(
|
|
223
|
-
"allowed_function_names"
|
|
224
|
-
)
|
|
225
|
-
else:
|
|
226
|
-
raise ValueError(
|
|
227
|
-
f"Unrecognized tool choice format:\n\n{tool_choice=}\n\nShould match "
|
|
228
|
-
f"Google GenerativeAI ToolConfig or FunctionCallingConfig format."
|
|
229
|
-
)
|
|
230
|
-
else:
|
|
231
|
-
raise ValueError(f"Unrecognized tool choice format:\n\n{tool_choice=}")
|
|
232
|
-
return _ToolConfigDict(
|
|
233
|
-
function_calling_config={
|
|
234
|
-
"mode": mode,
|
|
235
|
-
"allowed_function_names": allowed_function_names,
|
|
236
|
-
}
|
|
237
|
-
)
|
|
File without changes
|
|
File without changes
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/__init__.py
RENAMED
|
File without changes
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/_common.py
RENAMED
|
File without changes
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/_enums.py
RENAMED
|
File without changes
|
|
File without changes
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/_image_utils.py
RENAMED
|
File without changes
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/genai_aqa.py
RENAMED
|
File without changes
|
|
File without changes
|
{langchain_google_genai-1.0.6 → langchain_google_genai-1.0.7}/langchain_google_genai/py.typed
RENAMED
|
File without changes
|