Skip to content

Commit

Permalink
Merge branch 'cz/imp-perf' of github.com:langflow-ai/langflow into cz…
Browse files Browse the repository at this point in the history
…/imp-perf
  • Loading branch information
Cristhianzl committed Dec 16, 2024
2 parents c3a7aec + 61539e9 commit 0cd1cf5
Show file tree
Hide file tree
Showing 29 changed files with 444 additions and 100 deletions.
17 changes: 9 additions & 8 deletions src/backend/base/langflow/base/agents/agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ class LCAgentComponent(Component):
),
MultilineInput(
name="agent_description",
display_name="Agent Description",
display_name="Agent Description [Deprecated]",
info=(
"The description of the agent. This is only used when in Tool Mode. "
f"Defaults to '{DEFAULT_TOOLS_DESCRIPTION}' and tools are added dynamically."
f"Defaults to '{DEFAULT_TOOLS_DESCRIPTION}' and tools are added dynamically. "
"This feature is deprecated and will be removed in future versions."
),
advanced=True,
value=DEFAULT_TOOLS_DESCRIPTION,
Expand Down Expand Up @@ -236,11 +237,11 @@ def to_toolkit(self) -> list[Tool]:
component_toolkit = _get_component_toolkit()
tools_names = self._build_tools_names()
agent_description = self.get_tool_description()
# Check if tools_description is the default value
if agent_description == DEFAULT_TOOLS_DESCRIPTION:
description = f"{agent_description}{tools_names}"
else:
description = agent_description
return component_toolkit(component=self).get_tools(
# TODO: Agent Description Depreciated Feature to be removed
description = f"{agent_description}{tools_names}"
tools = component_toolkit(component=self).get_tools(
tool_name=self.get_tool_name(), tool_description=description, callbacks=self.get_langchain_callbacks()
)
if hasattr(self, "tools_metadata"):
tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)
return tools
32 changes: 27 additions & 5 deletions src/backend/base/langflow/base/tools/component_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ def get_tools(
args_schema=args_schema,
handle_tool_error=True,
callbacks=callbacks,
tags=[formatted_name],
)
)
else:
Expand All @@ -229,6 +230,7 @@ def get_tools(
args_schema=args_schema,
handle_tool_error=True,
callbacks=callbacks,
tags=[formatted_name],
)
)
if len(tools) == 1 and (tool_name or tool_description):
Expand All @@ -243,17 +245,37 @@ def get_tools(
raise ValueError(msg)
return tools

def get_tools_metadata_dictionary(self) -> dict:
if isinstance(self.metadata, pd.DataFrame):
try:
return {
record["tags"][0]: record
for record in self.metadata.to_dict(orient="records")
if record.get("tags")
}
except (KeyError, IndexError) as e:
msg = "Error processing metadata records: " + str(e)
raise ValueError(msg) from e
return {}

def update_tools_metadata(
self,
tools: list[BaseTool | StructuredTool],
) -> list[BaseTool]:
# update the tool_name and description according to the name and secriotion mentioned in the list
if isinstance(self.metadata, pd.DataFrame):
metadata_dict = self.metadata.to_dict(orient="records")
for tool, metadata in zip(tools, metadata_dict, strict=False):
if isinstance(tool, StructuredTool | BaseTool):
tool.name = metadata.get("name", tool.name)
tool.description = metadata.get("description", tool.description)
metadata_dict = self.get_tools_metadata_dictionary()
for tool in tools:
if isinstance(tool, StructuredTool | BaseTool) and tool.tags:
try:
tag = tool.tags[0]
except IndexError:
msg = "Tool tags cannot be empty."
raise ValueError(msg) from None
if tag in metadata_dict:
tool_metadata = metadata_dict[tag]
tool.name = tool_metadata.get("name", tool.name)
tool.description = tool_metadata.get("description", tool.description)
else:
msg = f"Expected a StructuredTool or BaseTool, got {type(tool)}"
raise TypeError(msg)
Expand Down
31 changes: 27 additions & 4 deletions src/backend/base/langflow/base/tools/constants.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
from langflow.schema.table import EditMode

TOOL_OUTPUT_NAME = "component_as_tool"
TOOL_OUTPUT_DISPLAY_NAME = "Toolset"
TOOLS_METADATA_INPUT_NAME = "tools_metadata"
TOOL_TABLE_SCHEMA = [
{
"name": "name",
"display_name": "Name",
"display_name": "Tool Name",
"type": "str",
"description": "Specify the name of the output field.",
"description": "Specify the name of the tool.",
"sortable": False,
"filterable": False,
"edit_mode": EditMode.INLINE,
},
{
"name": "description",
"display_name": "Description",
"display_name": "Tool Description",
"type": "str",
"description": "Describe the purpose of the output field.",
"description": "Describe the purpose of the tool.",
"sortable": False,
"filterable": False,
"edit_mode": EditMode.INLINE,
},
{
"name": "tags",
"display_name": "Tool Identifiers",
"type": "str",
"description": (
"These are the default identifiers for the tools and cannot be changed. "
"Tool Name and Tool Description are the only editable fields."
),
"disable_edit": True,
"sortable": False,
"filterable": False,
"edit_mode": EditMode.INLINE,
},
]

TOOLS_METADATA_INFO = "Use the table to configure the tools."
19 changes: 12 additions & 7 deletions src/backend/base/langflow/components/helpers/store_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class StoreMessageComponent(Component):
]

outputs = [
Output(display_name="Stored Messages", name="stored_messages", method="store_message"),
Output(display_name="Stored Message", name="stored_message", method="store_message"),
]

async def store_message(self) -> Message:
Expand All @@ -61,14 +61,19 @@ async def store_message(self) -> Message:
self.memory.session_id = message.session_id
lc_message = message.to_lc_message()
await self.memory.aadd_messages([lc_message])
stored = await self.memory.aget_messages()
stored = [Message.from_lc_message(m) for m in stored]
stored_message = await self.memory.aget_messages()
stored_message = [Message.from_lc_message(m) for m in stored_message]
if message.sender:
stored = [m for m in stored if m.sender == message.sender]
stored_message = [m for m in stored_message if m.sender == message.sender]
else:
await astore_message(message, flow_id=self.graph.flow_id)
stored = await aget_messages(
stored_messages = await aget_messages(
session_id=message.session_id, sender_name=message.sender_name, sender=message.sender
)
self.status = stored
return stored
if not stored_messages:
msg = "No messages were stored. Please ensure that the session ID and sender are properly set."
raise ValueError(msg)
stored_message = stored_messages[0]

self.status = stored_message
return stored_message
37 changes: 29 additions & 8 deletions src/backend/base/langflow/components/logic/conditional_router.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

from langflow.custom import Component
from langflow.io import BoolInput, DropdownInput, IntInput, MessageInput, MessageTextInput, Output
from langflow.schema.message import Message
Expand Down Expand Up @@ -27,16 +29,16 @@ def __init__(self, *args, **kwargs):
DropdownInput(
name="operator",
display_name="Operator",
options=["equals", "not equals", "contains", "starts with", "ends with"],
options=["equals", "not equals", "contains", "starts with", "ends with", "matches regex"],
info="The operator to apply for comparing the texts.",
value="equals",
real_time_refresh=True,
),
BoolInput(
name="case_sensitive",
display_name="Case Sensitive",
info="If true, the comparison will be case sensitive.",
value=False,
advanced=True,
),
MessageInput(
name="message",
Expand All @@ -49,6 +51,7 @@ def __init__(self, *args, **kwargs):
display_name="Max Iterations",
info="The maximum number of iterations for the conditional router.",
value=10,
advanced=True,
),
DropdownInput(
name="default_route",
Expand All @@ -69,7 +72,7 @@ def _pre_run_setup(self):
self.__iteration_updated = False

def evaluate_condition(self, input_text: str, match_text: str, operator: str, *, case_sensitive: bool) -> bool:
if not case_sensitive:
if not case_sensitive and operator != "matches regex":
input_text = input_text.lower()
match_text = match_text.lower()

Expand All @@ -83,18 +86,22 @@ def evaluate_condition(self, input_text: str, match_text: str, operator: str, *,
return input_text.startswith(match_text)
if operator == "ends with":
return input_text.endswith(match_text)
if operator == "matches regex":
try:
return bool(re.match(match_text, input_text))
except re.error:
return False # Return False if the regex is invalid
return False

def iterate_and_stop_once(self, route_to_stop: str):
if not self.__iteration_updated:
self.update_ctx({f"{self._id}_iteration": self.ctx.get(f"{self._id}_iteration", 0) + 1})
self.__iteration_updated = True
if self.ctx.get(f"{self._id}_iteration", 0) >= self.max_iterations and route_to_stop == self.default_route:
# We need to stop the other route
route_to_stop = "true_result" if route_to_stop == "false_result" else "false_result"
self.stop(route_to_stop)

def true_response(self) -> Message | str:
def true_response(self) -> Message:
result = self.evaluate_condition(
self.input_text, self.match_text, self.operator, case_sensitive=self.case_sensitive
)
Expand All @@ -103,9 +110,9 @@ def true_response(self) -> Message | str:
self.iterate_and_stop_once("false_result")
return self.message
self.iterate_and_stop_once("true_result")
return ""
return Message(content="")

def false_response(self) -> Message | str:
def false_response(self) -> Message:
result = self.evaluate_condition(
self.input_text, self.match_text, self.operator, case_sensitive=self.case_sensitive
)
Expand All @@ -114,4 +121,18 @@ def false_response(self) -> Message | str:
self.iterate_and_stop_once("true_result")
return self.message
self.iterate_and_stop_once("false_result")
return ""
return Message(content="")

def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None) -> dict:
if field_name == "operator":
if field_value == "matches regex":
if "case_sensitive" in build_config:
del build_config["case_sensitive"]
# Ensure case_sensitive is present for all other operators
elif "case_sensitive" not in build_config:
case_sensitive_input = next(
(input_field for input_field in self.inputs if input_field.name == "case_sensitive"), None
)
if case_sensitive_input:
build_config["case_sensitive"] = case_sensitive_input.to_dict()
return build_config
20 changes: 18 additions & 2 deletions src/backend/base/langflow/custom/custom_component/component.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
TOOL_OUTPUT_DISPLAY_NAME,
TOOL_OUTPUT_NAME,
TOOL_TABLE_SCHEMA,
TOOLS_METADATA_INFO,
TOOLS_METADATA_INPUT_NAME,
)
from langflow.custom.tree_visitor import RequiredInputsVisitor
Expand All @@ -30,6 +31,7 @@
from langflow.schema.data import Data
from langflow.schema.message import ErrorMessage, Message
from langflow.schema.properties import Source
from langflow.schema.table import FieldParserType, TableOptions
from langflow.services.tracing.schema import Log
from langflow.template.field.base import UNDEFINED, Input, Output
from langflow.template.frontend_node.custom_components import ComponentFrontendNode
Expand Down Expand Up @@ -1173,7 +1175,7 @@ def _build_tools_metadata_input(self):
tool_data = (
self.tools_metadata
if hasattr(self, TOOLS_METADATA_INPUT_NAME)
else [{"name": tool.name, "description": tool.description} for tool in tools]
else [{"name": tool.name, "description": tool.description, "tags": tool.tags} for tool in tools]
)
try:
from langflow.io import TableInput
Expand All @@ -1183,8 +1185,22 @@ def _build_tools_metadata_input(self):

return TableInput(
name=TOOLS_METADATA_INPUT_NAME,
display_name="Tools Metadata",
info=TOOLS_METADATA_INFO,
display_name="Toolset configuration",
real_time_refresh=True,
table_schema=TOOL_TABLE_SCHEMA,
value=tool_data,
trigger_icon="Hammer",
trigger_text="Open toolset",
table_options=TableOptions(
block_add=True,
block_delete=True,
block_edit=True,
block_sort=True,
block_filter=True,
block_hide=True,
block_select=True,
hide_options=True,
field_parsers={"name": FieldParserType.SNAKE_CASE},
),
)
Original file line number Diff line number Diff line change
Expand Up @@ -1656,9 +1656,9 @@
"agent_description": {
"_input_type": "MultilineInput",
"advanced": true,
"display_name": "Agent Description",
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically.",
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
"input_types": [
"Message"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1900,9 +1900,9 @@
"agent_description": {
"_input_type": "MultilineInput",
"advanced": true,
"display_name": "Agent Description",
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically.",
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
"input_types": [
"Message"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2147,9 +2147,9 @@
"agent_description": {
"_input_type": "MultilineInput",
"advanced": true,
"display_name": "Agent Description",
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically.",
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
"input_types": [
"Message"
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -721,9 +721,9 @@
"agent_description": {
"_input_type": "MultilineInput",
"advanced": true,
"display_name": "Agent Description",
"display_name": "Agent Description [Deprecated]",
"dynamic": false,
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically.",
"info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.",
"input_types": [
"Message"
],
Expand Down
Loading

0 comments on commit 0cd1cf5

Please sign in to comment.