langflow/src/backend/base/langflow/interface/tools/base.py
Gabriel Luiz Freitas Almeida b0308336c2
Fix State Service not loading when using load_flow_from_json (#1661)
* Refactor test_loading.py to improve code readability and maintainability

* Refactor code in test_template.py, __main__.py, and utils.py to improve code readability and maintainability

* Fix logger.configure() to disable logging when disable flag is True

* Refactor validate_icon function to use emoji library for emoji validation in model.py

* Refactor import statements in base.py files to improve code organization and maintainability

* Refactor state_manager.py to handle error when getting state service and use InMemoryStateService as fallback

* Refactor load_flow_from_json function in load.py to configure logs and load services

* Add test_run_flow_from_json_object function to test_loading.py

* Refactor langflow.processing.process.py and langflow.schema.graph.py

* Set all streaming to false in run_flow_from_json function

* Refactor import statements in base.py files to improve code organization and maintainability

* Refactor arun function in base.py to handle event loop and async execution

* Add docstring to run_flow_from_json

* Refactor import statements in base.py files to use logger in langflow interface

* Refactor build method in ChatOutput and TextInput classes to use build_with_record

* Refactor import statements in base.py files to improve code organization and maintainability

* Refactor import statements in PythonREPLTool.py for improved code organization and maintainability

* Refactor build method in TextOutput class to include optional record_template parameter

* Refactor build method in ChatComponent class to include build_no_record method

* Refactor input_value parameter in TextInput build method to use Text type

* Refactor import statements in FlowTool.py for improved code organization and maintainability

* Bump langflow-base version to 0.0.25 and add asyncer dependency

* Refactor code in multiple files for improved organization and maintainability

* Refactor import statements in multiple files for improved code organization and maintainability
2024-04-10 11:56:37 -03:00

170 lines
5.7 KiB
Python

from typing import Dict, List, Optional
from langchain.agents.load_tools import _EXTRA_LLM_TOOLS, _EXTRA_OPTIONAL_TOOLS, _LLM_TOOLS
from langflow.interface.base import LangChainTypeCreator
from langflow.interface.tools.constants import ALL_TOOLS_NAMES, CUSTOM_TOOLS, FILE_TOOLS, OTHER_TOOLS
from langflow.interface.tools.util import get_tool_params
from langflow.legacy_custom import customs
from langflow.services.deps import get_settings_service
from langflow.template.field.base import TemplateField
from langflow.template.template.base import Template
from langflow.utils import util
from langflow.utils.logger import logger
from langflow.interface.utils import build_template_from_class
TOOL_INPUTS = {
"str": TemplateField(
field_type="str",
required=True,
is_list=False,
show=True,
placeholder="",
value="",
),
"llm": TemplateField(field_type="BaseLanguageModel", required=True, is_list=False, show=True),
"func": TemplateField(
field_type="Callable",
required=True,
is_list=False,
show=True,
multiline=True,
),
"code": TemplateField(
field_type="str",
required=True,
is_list=False,
show=True,
value="",
multiline=True,
),
"path": TemplateField(
field_type="file",
required=True,
is_list=False,
show=True,
value="",
file_types=[".json", ".yaml", ".yml"],
),
}
class ToolCreator(LangChainTypeCreator):
type_name: str = "tools"
tools_dict: Optional[Dict] = None
@property
def type_to_loader_dict(self) -> Dict:
settings_service = get_settings_service()
if self.tools_dict is None:
all_tools = {}
for tool, tool_fcn in ALL_TOOLS_NAMES.items():
try:
tool_params = get_tool_params(tool_fcn)
except Exception:
logger.error(f"Error getting params for tool {tool}")
continue
tool_name = tool_params.get("name") or tool
if tool_name in settings_service.settings.TOOLS or settings_service.settings.DEV:
if tool_name == "JsonSpec":
tool_params["path"] = tool_params.pop("dict_") # type: ignore
all_tools[tool_name] = {
"type": tool,
"params": tool_params,
"fcn": tool_fcn,
}
self.tools_dict = all_tools
return self.tools_dict
def get_signature(self, name: str) -> Optional[Dict]:
"""Get the signature of a tool."""
base_classes = ["Tool", "BaseTool"]
fields = []
params = []
tool_params = {}
# Raise error if name is not in tools
if name not in self.type_to_loader_dict.keys():
raise ValueError("Tool not found")
tool_type: str = self.type_to_loader_dict[name]["type"] # type: ignore
# if tool_type in _BASE_TOOLS.keys():
# params = []
if tool_type in _LLM_TOOLS.keys():
params = ["llm"]
elif tool_type in _EXTRA_LLM_TOOLS.keys():
extra_keys = _EXTRA_LLM_TOOLS[tool_type][1]
params = ["llm"] + extra_keys
elif tool_type in _EXTRA_OPTIONAL_TOOLS.keys():
extra_keys = _EXTRA_OPTIONAL_TOOLS[tool_type][1]
params = extra_keys
# elif tool_type == "Tool":
# params = ["name", "description", "func"]
elif tool_type in CUSTOM_TOOLS:
# Get custom tool params
params = self.type_to_loader_dict[name]["params"] # type: ignore
base_classes = ["Callable"]
if node := customs.get_custom_nodes("tools").get(tool_type):
return node
elif tool_type in FILE_TOOLS:
params = self.type_to_loader_dict[name]["params"] # type: ignore
base_classes += [name]
elif tool_type in OTHER_TOOLS:
tool_dict = build_template_from_class(tool_type, OTHER_TOOLS)
fields = tool_dict["template"]
# _type is the only key in fields
# return None
if len(fields) == 1 and "_type" in fields:
return None
# Pop unnecessary fields and add name
fields.pop("_type") # type: ignore
fields.pop("return_direct", None) # type: ignore
fields.pop("verbose", None) # type: ignore
tool_params = {
"name": fields.pop("name")["value"], # type: ignore
"description": fields.pop("description")["value"], # type: ignore
}
fields = [
TemplateField(name=name, field_type=field["type"], **field)
for name, field in fields.items() # type: ignore
]
base_classes += tool_dict["base_classes"]
# Copy the field and add the name
for param in params:
field = TOOL_INPUTS.get(param, TOOL_INPUTS["str"]).copy()
field.name = param
field.advanced = False
if param == "aiosession":
field.show = False
field.required = False
fields.append(field)
template = Template(fields=fields, type_name=tool_type)
tool_params = {**tool_params, **self.type_to_loader_dict[name]["params"]}
return {
"template": util.format_dict(template.to_dict()),
**tool_params,
"base_classes": base_classes,
}
def to_list(self) -> List[str]:
"""List all load tools"""
return list(self.type_to_loader_dict.keys())
tool_creator = ToolCreator()