feat: add ComponentTool to support converting Component to Tool (#3412)
* feat: Add ComponentTool to convert a Component to a Tool * test(component): add unit test for ComponentTool with ChatInput input. * feat: Add method to convert Component to ComponentTool. * feat: Add unit test for ChatInput to Tool conversion. * chore: add comment * test: fix assertion --------- Co-authored-by: italojohnny <italojohnnydosanjos@gmail.com>
This commit is contained in:
parent
149c96d26c
commit
75dbb68dfc
4 changed files with 125 additions and 0 deletions
41
src/backend/base/langflow/base/tools/component_tool.py
Normal file
41
src/backend/base/langflow/base/tools/component_tool.py
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
from typing import Any
|
||||
|
||||
from langchain_core.tools import BaseTool, ToolException
|
||||
|
||||
from langflow.custom.custom_component.component import Component
|
||||
|
||||
|
||||
class ComponentTool(BaseTool):
|
||||
name: str
|
||||
description: str
|
||||
component: "Component"
|
||||
|
||||
def __init__(self, component: "Component") -> None:
|
||||
"""Initialize the tool."""
|
||||
from langflow.io.schema import create_input_schema
|
||||
|
||||
name = component.name or component.__class__.__name__
|
||||
description = component.description or ""
|
||||
args_schema = create_input_schema(component.inputs)
|
||||
super().__init__(name=name, description=description, args_schema=args_schema, component=component)
|
||||
# self.component = component
|
||||
|
||||
@property
|
||||
def args(self) -> dict:
|
||||
schema = self.get_input_schema()
|
||||
return schema.schema()["properties"]
|
||||
|
||||
def _run(
|
||||
self,
|
||||
*args: Any,
|
||||
**kwargs: Any,
|
||||
) -> dict:
|
||||
"""Use the tool."""
|
||||
try:
|
||||
results, _ = self.component(**kwargs)
|
||||
return results
|
||||
except Exception as e:
|
||||
raise ToolException(f"Error running {self.name}: {e}")
|
||||
|
||||
|
||||
ComponentTool.update_forward_refs()
|
||||
|
|
@ -653,3 +653,9 @@ class Component(CustomComponent):
|
|||
|
||||
def _get_fallback_input(self, **kwargs):
|
||||
return Input(**kwargs)
|
||||
|
||||
def to_tool(self):
|
||||
# TODO: This is a temporary solution to avoid circular imports
|
||||
from langflow.base.tools.component_tool import ComponentTool
|
||||
|
||||
return ComponentTool(component=self)
|
||||
|
|
|
|||
62
src/backend/tests/unit/base/tools/test_component_tool.py
Normal file
62
src/backend/tests/unit/base/tools/test_component_tool.py
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
import pytest
|
||||
|
||||
from langflow.base.tools.component_tool import ComponentTool
|
||||
from langflow.components.inputs.ChatInput import ChatInput
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
pass
|
||||
|
||||
|
||||
def test_component_tool():
|
||||
chat_input = ChatInput()
|
||||
component_tool = ComponentTool(component=chat_input)
|
||||
assert component_tool.name == "ChatInput"
|
||||
assert component_tool.description == chat_input.description
|
||||
assert component_tool.args == {
|
||||
"input_value": {
|
||||
"default": "",
|
||||
"description": "Message to be passed as input.",
|
||||
"title": "Input Value",
|
||||
"type": "string",
|
||||
},
|
||||
"should_store_message": {
|
||||
"default": True,
|
||||
"description": "Store the message in the history.",
|
||||
"title": "Should Store Message",
|
||||
"type": "boolean",
|
||||
},
|
||||
"sender": {
|
||||
"default": "User",
|
||||
"description": "Type of sender.",
|
||||
"enum": ["Machine", "User"],
|
||||
"title": "Sender",
|
||||
"type": "string",
|
||||
},
|
||||
"sender_name": {
|
||||
"default": "User",
|
||||
"description": "Name of the sender.",
|
||||
"title": "Sender Name",
|
||||
"type": "string",
|
||||
},
|
||||
"session_id": {
|
||||
"default": "",
|
||||
"description": "The session ID of the chat. If empty, the current session ID parameter will be used.",
|
||||
"title": "Session Id",
|
||||
"type": "string",
|
||||
},
|
||||
"files": {
|
||||
"default": "",
|
||||
"description": "Files to be sent with the message.",
|
||||
"items": {"type": "string"},
|
||||
"title": "Files",
|
||||
"type": "array",
|
||||
},
|
||||
}
|
||||
assert component_tool.component == chat_input
|
||||
|
||||
result = component_tool.invoke(input=dict(input_value="test"))
|
||||
assert isinstance(result, dict)
|
||||
assert hasattr(result["message"], "get_text")
|
||||
assert result["message"].get_text() == "test"
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
import pytest
|
||||
|
||||
from langflow.components.inputs.ChatInput import ChatInput
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def client():
|
||||
pass
|
||||
|
||||
|
||||
def test_component_to_tool():
|
||||
chat_input = ChatInput()
|
||||
tool = chat_input.to_tool()
|
||||
assert tool.name == "ChatInput"
|
||||
assert tool.description == "Get chat inputs from the Playground."
|
||||
assert tool.component._id == chat_input._id
|
||||
Loading…
Add table
Add a link
Reference in a new issue