feat: fix integration with newest langchain version
This commit is contained in:
parent
2decce7f6b
commit
3ec4257a63
5 changed files with 156 additions and 126 deletions
|
|
@ -98,7 +98,15 @@ def list_memories():
|
|||
def list_tools():
|
||||
"""List all load tools"""
|
||||
|
||||
return [
|
||||
util.get_tool_params(util.get_tools_dict(tool))["name"]
|
||||
for tool in get_all_tool_names()
|
||||
]
|
||||
tools = []
|
||||
|
||||
for tool in get_all_tool_names():
|
||||
if tool_params := util.get_tool_params(util.get_tools_dict(tool)):
|
||||
tools.append(tool_params["name"])
|
||||
|
||||
return tools
|
||||
|
||||
# return [
|
||||
# util.get_tool_params(util.get_tools_dict(tool))["name"]
|
||||
# for tool in get_all_tool_names()
|
||||
# ]
|
||||
|
|
|
|||
14
langflow/backend/poetry.lock
generated
14
langflow/backend/poetry.lock
generated
|
|
@ -524,12 +524,12 @@ test = ["ipykernel", "pre-commit", "pytest", "pytest-cov", "pytest-timeout"]
|
|||
|
||||
[[package]]
|
||||
name = "langchain"
|
||||
version = "0.0.86"
|
||||
version = "0.0.100"
|
||||
description = "Building applications with LLMs through composability"
|
||||
category = "main"
|
||||
optional = false
|
||||
python-versions = ">=3.8.1,<4.0"
|
||||
develop = false
|
||||
develop = true
|
||||
|
||||
[package.dependencies]
|
||||
aiohttp = "^3.8.3"
|
||||
|
|
@ -542,14 +542,12 @@ SQLAlchemy = "^1"
|
|||
tenacity = "^8.1.0"
|
||||
|
||||
[package.extras]
|
||||
all = ["anthropic (>=0.2.2,<0.3.0)", "beautifulsoup4 (>=4,<5)", "cohere (>=3,<4)", "elasticsearch (>=8,<9)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-search-results (>=2,<3)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "manifest-ml (>=0.0.1,<0.0.2)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "openai (>=0,<1)", "pinecone-client (>=2,<3)", "pypdf (>=3.4.0,<4.0.0)", "qdrant-client (>=0.11.7,<0.12.0)", "redis (>=4,<5)", "sentence-transformers (>=2,<3)", "spacy (>=3,<4)", "tensorflow-text (>=2.11.0,<3.0.0)", "tiktoken (>=0,<1)", "torch (>=1,<2)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"]
|
||||
all = ["anthropic (>=0.2.2,<0.3.0)", "beautifulsoup4 (>=4,<5)", "cohere (>=3,<4)", "elasticsearch (>=8,<9)", "faiss-cpu (>=1,<2)", "google-api-python-client (==2.70.0)", "google-search-results (>=2,<3)", "huggingface_hub (>=0,<1)", "jinja2 (>=3,<4)", "manifest-ml (>=0.0.1,<0.0.2)", "networkx (>=2.6.3,<3.0.0)", "nlpcloud (>=1,<2)", "nltk (>=3,<4)", "nomic (>=1.0.43,<2.0.0)", "openai (>=0,<1)", "opensearch-py (>=2.0.0,<3.0.0)", "pinecone-client (>=2,<3)", "pypdf (>=3.4.0,<4.0.0)", "qdrant-client (>=1.0.4,<2.0.0)", "redis (>=4,<5)", "sentence-transformers (>=2,<3)", "spacy (>=3,<4)", "tensorflow-text (>=2.11.0,<3.0.0)", "tiktoken (>=0,<1)", "torch (>=1,<2)", "transformers (>=4,<5)", "weaviate-client (>=3,<4)", "wikipedia (>=1,<2)", "wolframalpha (==5.0.0)"]
|
||||
llms = ["anthropic (>=0.2.2,<0.3.0)", "cohere (>=3,<4)", "huggingface_hub (>=0,<1)", "manifest-ml (>=0.0.1,<0.0.2)", "nlpcloud (>=1,<2)", "openai (>=0,<1)", "torch (>=1,<2)", "transformers (>=4,<5)"]
|
||||
|
||||
[package.source]
|
||||
type = "git"
|
||||
url = "https://github.com/ibiscp/langchain.git"
|
||||
reference = "ibis"
|
||||
resolved_reference = "059e90090639e3c8c23928f1799e715b5635f681"
|
||||
type = "directory"
|
||||
url = "../../../langchain"
|
||||
|
||||
[[package]]
|
||||
name = "marshmallow"
|
||||
|
|
@ -1101,7 +1099,7 @@ multidict = ">=4.0"
|
|||
[metadata]
|
||||
lock-version = "1.1"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "fb4b97be211d190c4feff42124fce6062b8717373d32b4894ae53f760742faaa"
|
||||
content-hash = "37ef2fda1358fdb0b52d9584f0fc903a9581310cc271c5bbfb79b6085176bf2e"
|
||||
|
||||
[metadata.files]
|
||||
aiohttp = [
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ uvicorn = "^0.20.0"
|
|||
beautifulsoup4 = "^4.11.2"
|
||||
google-search-results = "^2.4.1"
|
||||
google-api-python-client = "^2.79.0"
|
||||
langchain = {git = "https://github.com/ibiscp/langchain.git", rev = "ibis"}
|
||||
langchain = {path = "../../../langchain", develop = true}
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^23.1.0"
|
||||
|
|
|
|||
|
|
@ -18,93 +18,13 @@ router = APIRouter(
|
|||
)
|
||||
|
||||
|
||||
def build_template_from_function(name: str, type_to_loader_dict: dict):
|
||||
classes = [
|
||||
item.__annotations__["return"].__name__ for item in type_to_loader_dict.values()
|
||||
]
|
||||
|
||||
# Raise error if name is not in chains
|
||||
if name not in classes:
|
||||
raise ValueError(f"{name} not found")
|
||||
|
||||
for _type, v in type_to_loader_dict.items():
|
||||
if v.__annotations__["return"].__name__ == name:
|
||||
_class = v.__annotations__["return"]
|
||||
|
||||
docs = util.get_class_doc(_class)
|
||||
|
||||
variables = {"_type": _type}
|
||||
for name, value in _class.__fields__.items():
|
||||
if name in ["callback_manager", "requests_wrapper"]:
|
||||
continue
|
||||
variables[name] = {}
|
||||
for name_, value_ in value.__repr_args__():
|
||||
if name_ == "default_factory":
|
||||
try:
|
||||
variables[name]["default"] = util.get_default_factory(
|
||||
module=_class.__base__.__module__, function=value_
|
||||
)
|
||||
except Exception:
|
||||
variables[name]["default"] = None
|
||||
elif name_ not in ["name"]:
|
||||
variables[name][name_] = value_
|
||||
|
||||
variables[name]["placeholder"] = (
|
||||
docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
)
|
||||
|
||||
return {
|
||||
"template": util.format_dict(variables),
|
||||
"description": docs["Description"],
|
||||
"base_classes": util.get_base_classes(_class),
|
||||
}
|
||||
|
||||
|
||||
def build_template_from_class(name: str, type_to_cls_dict: dict):
|
||||
classes = [item.__name__ for item in type_to_cls_dict.values()]
|
||||
|
||||
# Raise error if name is not in chains
|
||||
if name not in classes:
|
||||
raise ValueError(f"{name} not found.")
|
||||
|
||||
for _type, v in type_to_cls_dict.items():
|
||||
if v.__name__ == name:
|
||||
_class = v
|
||||
|
||||
docs = util.get_class_doc(_class)
|
||||
|
||||
variables = {"_type": _type}
|
||||
for name, value in _class.__fields__.items():
|
||||
if name in ["callback_manager"]:
|
||||
continue
|
||||
variables[name] = {}
|
||||
for name_, value_ in value.__repr_args__():
|
||||
if name_ == "default_factory":
|
||||
try:
|
||||
variables[name]["default"] = util.get_default_factory(
|
||||
module=_class.__base__.__module__, function=value_
|
||||
)
|
||||
except Exception:
|
||||
variables[name]["default"] = None
|
||||
elif name_ not in ["name"]:
|
||||
variables[name][name_] = value_
|
||||
|
||||
variables[name]["placeholder"] = (
|
||||
docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
)
|
||||
|
||||
return {
|
||||
"template": util.format_dict(variables),
|
||||
"description": docs["Description"],
|
||||
"base_classes": util.get_base_classes(_class),
|
||||
}
|
||||
|
||||
|
||||
@router.get("/chain")
|
||||
def get_chain(name: str):
|
||||
"""Get the signature of a chain."""
|
||||
try:
|
||||
return build_template_from_function(name, chains.loading.type_to_loader_dict)
|
||||
return util.build_template_from_function(
|
||||
name, chains.loading.type_to_loader_dict
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=404, detail="Chain not found") from exc
|
||||
|
||||
|
|
@ -113,7 +33,7 @@ def get_chain(name: str):
|
|||
def get_agent(name: str):
|
||||
"""Get the signature of an agent."""
|
||||
try:
|
||||
return build_template_from_class(name, agents.loading.AGENT_TO_CLASS)
|
||||
return util.build_template_from_class(name, agents.loading.AGENT_TO_CLASS)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=404, detail="Agent not found") from exc
|
||||
|
||||
|
|
@ -122,7 +42,9 @@ def get_agent(name: str):
|
|||
def get_prompt(name: str):
|
||||
"""Get the signature of a prompt."""
|
||||
try:
|
||||
return build_template_from_function(name, prompts.loading.type_to_loader_dict)
|
||||
return util.build_template_from_function(
|
||||
name, prompts.loading.type_to_loader_dict
|
||||
)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=404, detail="Prompt not found") from exc
|
||||
|
||||
|
|
@ -131,7 +53,7 @@ def get_prompt(name: str):
|
|||
def get_llm(name: str):
|
||||
"""Get the signature of an llm."""
|
||||
try:
|
||||
return build_template_from_class(name, llms.type_to_cls_dict)
|
||||
return util.build_template_from_class(name, llms.type_to_cls_dict)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=404, detail="LLM not found") from exc
|
||||
|
||||
|
|
@ -152,7 +74,7 @@ def get_llm(name: str):
|
|||
def get_memory(name: str):
|
||||
"""Get the signature of a memory."""
|
||||
try:
|
||||
return build_template_from_class(name, memories.type_to_cls_dict)
|
||||
return util.build_template_from_class(name, memories.type_to_cls_dict)
|
||||
except ValueError as exc:
|
||||
raise HTTPException(status_code=404, detail="Memory not found") from exc
|
||||
|
||||
|
|
@ -173,10 +95,10 @@ def get_memory(name: str):
|
|||
def get_tool(name: str):
|
||||
"""Get the signature of a tool."""
|
||||
|
||||
all_tools = {
|
||||
util.get_tool_params(util.get_tools_dict(tool))["name"]: tool
|
||||
for tool in get_all_tool_names()
|
||||
}
|
||||
all_tools = {}
|
||||
for tool in get_all_tool_names():
|
||||
if tool_params := util.get_tool_params(util.get_tools_dict(tool)):
|
||||
all_tools[tool_params["name"]] = tool
|
||||
|
||||
# Raise error if name is not in tools
|
||||
if name not in all_tools.keys():
|
||||
|
|
@ -185,7 +107,7 @@ def get_tool(name: str):
|
|||
type_dict = {
|
||||
"str": {
|
||||
"type": "str",
|
||||
"required": True,
|
||||
"required": False,
|
||||
"list": False,
|
||||
"show": True,
|
||||
"placeholder": "",
|
||||
|
|
@ -218,9 +140,3 @@ def get_tool(name: str):
|
|||
**util.get_tool_params(util.get_tools_dict(tool_type)),
|
||||
"base_classes": ["Tool"],
|
||||
}
|
||||
|
||||
|
||||
# {"template": signature.tool(tool), **values}
|
||||
# for tool, values in tools.items()
|
||||
# }
|
||||
# return {k: util.get_tool_params(v) for k, v in merged_dict.items()}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@ import ast
|
|||
import inspect
|
||||
import re
|
||||
import importlib
|
||||
|
||||
from langchain.agents.load_tools import *
|
||||
from langchain.agents.load_tools import (
|
||||
_BASE_TOOLS,
|
||||
_LLM_TOOLS,
|
||||
|
|
@ -11,6 +13,88 @@ from langchain.agents.load_tools import (
|
|||
from typing import Optional
|
||||
|
||||
|
||||
def build_template_from_function(name: str, type_to_loader_dict: dict):
|
||||
classes = [
|
||||
item.__annotations__["return"].__name__ for item in type_to_loader_dict.values()
|
||||
]
|
||||
|
||||
# Raise error if name is not in chains
|
||||
if name not in classes:
|
||||
raise ValueError(f"{name} not found")
|
||||
|
||||
for _type, v in type_to_loader_dict.items():
|
||||
if v.__annotations__["return"].__name__ == name:
|
||||
_class = v.__annotations__["return"]
|
||||
|
||||
docs = get_class_doc(_class)
|
||||
|
||||
variables = {"_type": _type}
|
||||
for name, value in _class.__fields__.items():
|
||||
if name in ["callback_manager", "requests_wrapper"]:
|
||||
continue
|
||||
variables[name] = {}
|
||||
for name_, value_ in value.__repr_args__():
|
||||
if name_ == "default_factory":
|
||||
try:
|
||||
variables[name]["default"] = get_default_factory(
|
||||
module=_class.__base__.__module__, function=value_
|
||||
)
|
||||
except Exception:
|
||||
variables[name]["default"] = None
|
||||
elif name_ not in ["name"]:
|
||||
variables[name][name_] = value_
|
||||
|
||||
variables[name]["placeholder"] = (
|
||||
docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
)
|
||||
|
||||
return {
|
||||
"template": format_dict(variables),
|
||||
"description": docs["Description"],
|
||||
"base_classes": get_base_classes(_class),
|
||||
}
|
||||
|
||||
|
||||
def build_template_from_class(name: str, type_to_cls_dict: dict):
|
||||
classes = [item.__name__ for item in type_to_cls_dict.values()]
|
||||
|
||||
# Raise error if name is not in chains
|
||||
if name not in classes:
|
||||
raise ValueError(f"{name} not found.")
|
||||
|
||||
for _type, v in type_to_cls_dict.items():
|
||||
if v.__name__ == name:
|
||||
_class = v
|
||||
|
||||
docs = get_class_doc(_class)
|
||||
|
||||
variables = {"_type": _type}
|
||||
for name, value in _class.__fields__.items():
|
||||
if name in ["callback_manager"]:
|
||||
continue
|
||||
variables[name] = {}
|
||||
for name_, value_ in value.__repr_args__():
|
||||
if name_ == "default_factory":
|
||||
try:
|
||||
variables[name]["default"] = get_default_factory(
|
||||
module=_class.__base__.__module__, function=value_
|
||||
)
|
||||
except Exception:
|
||||
variables[name]["default"] = None
|
||||
elif name_ not in ["name"]:
|
||||
variables[name][name_] = value_
|
||||
|
||||
variables[name]["placeholder"] = (
|
||||
docs["Attributes"][name] if name in docs["Attributes"] else ""
|
||||
)
|
||||
|
||||
return {
|
||||
"template": format_dict(variables),
|
||||
"description": docs["Description"],
|
||||
"base_classes": get_base_classes(_class),
|
||||
}
|
||||
|
||||
|
||||
def get_base_classes(cls):
|
||||
bases = cls.__bases__
|
||||
if not bases:
|
||||
|
|
@ -45,7 +129,7 @@ def get_tools_dict(name: Optional[str] = None):
|
|||
return tools[name] if name else tools
|
||||
|
||||
|
||||
def get_tool_params(func):
|
||||
def get_tool_params(func, **kwargs):
|
||||
# Parse the function code into an abstract syntax tree
|
||||
tree = ast.parse(inspect.getsource(func))
|
||||
|
||||
|
|
@ -54,19 +138,35 @@ def get_tool_params(func):
|
|||
# Find the first return statement
|
||||
if isinstance(node, ast.Return):
|
||||
tool = node.value
|
||||
if isinstance(tool, ast.Call) and tool.func.id == "Tool":
|
||||
if tool.keywords:
|
||||
tool_params = {}
|
||||
for keyword in tool.keywords:
|
||||
if keyword.arg == "name":
|
||||
tool_params["name"] = ast.literal_eval(keyword.value)
|
||||
elif keyword.arg == "description":
|
||||
tool_params["description"] = ast.literal_eval(keyword.value)
|
||||
return tool_params
|
||||
return {
|
||||
"name": ast.literal_eval(tool.args[0]),
|
||||
"description": ast.literal_eval(tool.args[2]),
|
||||
}
|
||||
if isinstance(tool, ast.Call):
|
||||
if tool.func.id == "Tool":
|
||||
if tool.keywords:
|
||||
tool_params = {}
|
||||
for keyword in tool.keywords:
|
||||
if keyword.arg == "name":
|
||||
tool_params["name"] = ast.literal_eval(keyword.value)
|
||||
elif keyword.arg == "description":
|
||||
tool_params["description"] = ast.literal_eval(
|
||||
keyword.value
|
||||
)
|
||||
return tool_params
|
||||
return {
|
||||
"name": ast.literal_eval(tool.args[0]),
|
||||
"description": ast.literal_eval(tool.args[2]),
|
||||
}
|
||||
else:
|
||||
# get the class object from the return statement
|
||||
try:
|
||||
class_obj = eval(
|
||||
compile(ast.Expression(tool), "<string>", "eval")
|
||||
)
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
return {
|
||||
"name": getattr(class_obj, "name"),
|
||||
"description": getattr(class_obj, "description"),
|
||||
}
|
||||
|
||||
# Return None if no return statement was found
|
||||
return None
|
||||
|
|
@ -162,7 +262,15 @@ def format_dict(d):
|
|||
value["show"] = bool(
|
||||
(value["required"] and key not in ["input_variables"])
|
||||
or key
|
||||
in ["allowed_tools", "verbose", "Memory", "memory", "prefix", "examples"]
|
||||
in [
|
||||
"allowed_tools",
|
||||
"verbose",
|
||||
"Memory",
|
||||
"memory",
|
||||
"prefix",
|
||||
"examples",
|
||||
"temperature",
|
||||
]
|
||||
or "api_key" in key
|
||||
)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue