Fix: simple agent template notes (#4709)

* delete-youtube-template

* update-simple-agent

* update-description

* docs-package-and-yarn-lock

* update-edges

* descriptions-and-markdown

* readme

* tags

* update

hotfix for the tool_kit mode component update

* Update Simple Agent.json

added project tags

* Update Simple Agent.spec.ts

Playwright test update

* Update Simple Agent.spec.ts

* Update starter-projects.spec.ts

remove  youtube flow  from templates in test

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
Co-authored-by: Edwin Jose <edwin.jose@datastax.com>
This commit is contained in:
Mendon Kissling 2024-11-20 15:24:37 -05:00 committed by GitHub
commit 3e57340cc4
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 413 additions and 1854 deletions

View file

@ -46,19 +46,28 @@ STARTER_FOLDER_DESCRIPTION = "Starter projects to help you get started in Langfl
def update_projects_components_with_latest_component_versions(project_data, all_types_dict):
# project data has a nodes key, which is a list of nodes
# we want to run through each node and see if it exists in the all_types_dict
# if so, we go into the template key and also get the template from all_types_dict
# and update it all
# Flatten the all_types_dict for easy access
all_types_dict_flat = {}
for category in all_types_dict.values():
for key, component in category.items():
all_types_dict_flat[key] = component # noqa: PERF403
node_changes_log = defaultdict(list)
project_data_copy = deepcopy(project_data)
for node in project_data_copy.get("nodes", []):
node_data = node.get("data").get("node")
node_type = node.get("data").get("type")
# Skip updating if tool_mode is True
if node_data.get("tool_mode", False):
continue
# Skip nodes with outputs of the specified format
# NOTE: to account for the fact that the Simple Agent has dynamic outputs
if any(output.get("types") == ["Tool"] for output in node_data.get("outputs", [])):
continue
if node_type in all_types_dict_flat:
latest_node = all_types_dict_flat.get(node_type)
latest_template = latest_node.get("template")

View file

@ -1082,7 +1082,7 @@
"zoom": 0.7749929474098888
}
},
"description": "Get started with a simple prompt engineering flow. Customize AI responses by adjusting the system prompt template to create varied personalities.",
"description": "Perform basic prompting with an OpenAI model.",
"endpoint_name": null,
"icon": "Braces",
"id": "1511c230-d446-43a7-bfc3-539e69ce05b8",

View file

@ -6,8 +6,64 @@
"className": "",
"data": {
"sourceHandle": {
"dataType": "YahooFinanceTool",
"id": "YahooFinanceTool-PzHUy",
"dataType": "ChatInput",
"id": "ChatInput-sTYr3",
"name": "message",
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "Agent-yGhD2",
"inputTypes": [
"Message"
],
"type": "str"
}
},
"id": "reactflow__edge-ChatInput-sTYr3{œdataTypeœ:œChatInputœ,œidœ:œChatInput-sTYr3œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-yGhD2{œfieldNameœ:œinput_valueœ,œidœ:œAgent-yGhD2œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
"source": "ChatInput-sTYr3",
"sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-sTYr3œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
"target": "Agent-yGhD2",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-yGhD2œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "Agent",
"id": "Agent-yGhD2",
"name": "response",
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-Tkzec",
"inputTypes": [
"Message"
],
"type": "str"
}
},
"id": "reactflow__edge-Agent-yGhD2{œdataTypeœ:œAgentœ,œidœ:œAgent-yGhD2œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Tkzec{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Tkzecœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"selected": false,
"source": "Agent-yGhD2",
"sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-yGhD2œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
"target": "ChatOutput-Tkzec",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Tkzecœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "CalculatorTool",
"id": "CalculatorTool-IfWT1",
"name": "api_build_tool",
"output_types": [
"Tool"
@ -15,7 +71,7 @@
},
"targetHandle": {
"fieldName": "tools",
"id": "Agent-KhAae",
"id": "Agent-yGhD2",
"inputTypes": [
"Tool",
"BaseTool",
@ -24,65 +80,42 @@
"type": "other"
}
},
"id": "reactflow__edge-YahooFinanceTool-PzHUy{œdataTypeœ:œYahooFinanceToolœ,œidœ:œYahooFinanceTool-PzHUyœ,œnameœ:œapi_build_toolœ,œoutput_typesœ:[œToolœ]}-Agent-KhAae{œfieldNameœ:œtoolsœ,œidœ:œAgent-KhAaeœ,œinputTypesœ:[œToolœ,œBaseToolœ,œStructuredToolœ],œtypeœ:œotherœ}",
"source": "YahooFinanceTool-PzHUy",
"sourceHandle": "{œdataTypeœ: œYahooFinanceToolœ, œidœ: œYahooFinanceTool-PzHUyœ, œnameœ: œapi_build_toolœ, œoutput_typesœ: [œToolœ]}",
"target": "Agent-KhAae",
"targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-KhAaeœ, œinputTypesœ: [œToolœ, œBaseToolœ, œStructuredToolœ], œtypeœ: œotherœ}"
"id": "reactflow__edge-CalculatorTool-IfWT1{œdataTypeœ:œCalculatorToolœ,œidœ:œCalculatorTool-IfWT1œ,œnameœ:œapi_build_toolœ,œoutput_typesœ:[œToolœ]}-Agent-yGhD2{œfieldNameœ:œtoolsœ,œidœ:œAgent-yGhD2œ,œinputTypesœ:[œToolœ,œBaseToolœ,œStructuredToolœ],œtypeœ:œotherœ}",
"selected": false,
"source": "CalculatorTool-IfWT1",
"sourceHandle": "{œdataTypeœ: œCalculatorToolœ, œidœ: œCalculatorTool-IfWT1œ, œnameœ: œapi_build_toolœ, œoutput_typesœ: [œToolœ]}",
"target": "Agent-yGhD2",
"targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-yGhD2œ, œinputTypesœ: [œToolœ, œBaseToolœ, œStructuredToolœ], œtypeœ: œotherœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "ChatInput",
"id": "ChatInput-dBek4",
"name": "message",
"dataType": "URL",
"id": "URL-FOPyh",
"name": "component_as_tool",
"output_types": [
"Message"
"Tool"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "Agent-KhAae",
"fieldName": "tools",
"id": "Agent-yGhD2",
"inputTypes": [
"Message"
"Tool",
"BaseTool",
"StructuredTool"
],
"type": "str"
"type": "other"
}
},
"id": "reactflow__edge-ChatInput-dBek4{œdataTypeœ:œChatInputœ,œidœ:œChatInput-dBek4œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-KhAae{œfieldNameœ:œinput_valueœ,œidœ:œAgent-KhAaeœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"source": "ChatInput-dBek4",
"sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-dBek4œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
"target": "Agent-KhAae",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-KhAaeœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
},
{
"animated": false,
"className": "",
"data": {
"sourceHandle": {
"dataType": "Agent",
"id": "Agent-KhAae",
"name": "response",
"output_types": [
"Message"
]
},
"targetHandle": {
"fieldName": "input_value",
"id": "ChatOutput-ULcvr",
"inputTypes": [
"Message"
],
"type": "str"
}
},
"id": "reactflow__edge-Agent-KhAae{œdataTypeœ:œAgentœ,œidœ:œAgent-KhAaeœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-ULcvr{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-ULcvrœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
"source": "Agent-KhAae",
"sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-KhAaeœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}",
"target": "ChatOutput-ULcvr",
"targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-ULcvrœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
"id": "reactflow__edge-URL-FOPyh{œdataTypeœ:œURLœ,œidœ:œURL-FOPyhœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-yGhD2{œfieldNameœ:œtoolsœ,œidœ:œAgent-yGhD2œ,œinputTypesœ:[œToolœ,œBaseToolœ,œStructuredToolœ],œtypeœ:œotherœ}",
"selected": false,
"source": "URL-FOPyh",
"sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-FOPyhœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}",
"target": "Agent-yGhD2",
"targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-yGhD2œ, œinputTypesœ: [œToolœ, œBaseToolœ, œStructuredToolœ], œtypeœ: œotherœ}"
}
],
"nodes": [
@ -90,7 +123,7 @@
"data": {
"description": "Define the agent's instructions, then enter a task to complete using tools.",
"display_name": "Agent",
"id": "Agent-KhAae",
"id": "Agent-yGhD2",
"node": {
"base_classes": [
"Message"
@ -133,6 +166,7 @@
"frozen": false,
"icon": "bot",
"legacy": false,
"lf_version": "1.1.0.dev4",
"metadata": {},
"output_types": [],
"outputs": [
@ -235,7 +269,7 @@
"show": true,
"title_case": false,
"type": "str",
"value": "OPENAI_API_KEY"
"value": ""
},
"code": {
"advanced": true,
@ -684,15 +718,15 @@
"type": "Agent"
},
"dragging": false,
"height": 650,
"id": "Agent-KhAae",
"height": 648,
"id": "Agent-yGhD2",
"position": {
"x": 2306.5155821255557,
"y": 335.1151630488809
"y": 332.5289520982579
},
"positionAbsolute": {
"x": 2306.5155821255557,
"y": 335.1151630488809
"y": 332.5289520982579
},
"selected": false,
"type": "genericNode",
@ -700,184 +734,7 @@
},
{
"data": {
"description": "Access financial data and market information using Yahoo Finance.",
"display_name": "Yahoo Finance Tool",
"id": "YahooFinanceTool-PzHUy",
"node": {
"base_classes": [
"Data",
"Tool"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
"description": "Access financial data and market information using Yahoo Finance.",
"display_name": "Yahoo Finance Tool",
"documentation": "",
"edited": false,
"field_order": [
"symbol",
"method",
"num_news"
],
"frozen": false,
"icon": "trending-up",
"legacy": false,
"lf_version": "1.0.19.post2",
"metadata": {},
"output_types": [],
"outputs": [
{
"cache": true,
"display_name": "Data",
"method": "run_model",
"name": "api_run_model",
"required_inputs": [],
"selected": "Data",
"types": [
"Data"
],
"value": "__UNDEFINED__"
},
{
"cache": true,
"display_name": "Tool",
"method": "build_tool",
"name": "api_build_tool",
"required_inputs": [],
"selected": "Tool",
"types": [
"Tool"
],
"value": "__UNDEFINED__"
}
],
"pinned": false,
"template": {
"_type": "Component",
"code": {
"advanced": true,
"dynamic": true,
"fileTypes": [],
"file_path": "",
"info": "",
"list": false,
"load_from_db": false,
"multiline": true,
"name": "code",
"password": false,
"placeholder": "",
"required": true,
"show": true,
"title_case": false,
"type": "code",
"value": "import ast\nimport pprint\nfrom enum import Enum\n\nimport yfinance as yf\nfrom langchain.tools import StructuredTool\nfrom langchain_core.tools import ToolException\nfrom loguru import logger\nfrom pydantic import BaseModel, Field\n\nfrom langflow.base.langchain_utilities.model import LCToolComponent\nfrom langflow.field_typing import Tool\nfrom langflow.inputs import DropdownInput, IntInput, MessageTextInput\nfrom langflow.schema import Data\n\n\nclass YahooFinanceMethod(Enum):\n GET_INFO = \"get_info\"\n GET_NEWS = \"get_news\"\n GET_ACTIONS = \"get_actions\"\n GET_ANALYSIS = \"get_analysis\"\n GET_BALANCE_SHEET = \"get_balance_sheet\"\n GET_CALENDAR = \"get_calendar\"\n GET_CASHFLOW = \"get_cashflow\"\n GET_INSTITUTIONAL_HOLDERS = \"get_institutional_holders\"\n GET_RECOMMENDATIONS = \"get_recommendations\"\n GET_SUSTAINABILITY = \"get_sustainability\"\n GET_MAJOR_HOLDERS = \"get_major_holders\"\n GET_MUTUALFUND_HOLDERS = \"get_mutualfund_holders\"\n GET_INSIDER_PURCHASES = \"get_insider_purchases\"\n GET_INSIDER_TRANSACTIONS = \"get_insider_transactions\"\n GET_INSIDER_ROSTER_HOLDERS = \"get_insider_roster_holders\"\n GET_DIVIDENDS = \"get_dividends\"\n GET_CAPITAL_GAINS = \"get_capital_gains\"\n GET_SPLITS = \"get_splits\"\n GET_SHARES = \"get_shares\"\n GET_FAST_INFO = \"get_fast_info\"\n GET_SEC_FILINGS = \"get_sec_filings\"\n GET_RECOMMENDATIONS_SUMMARY = \"get_recommendations_summary\"\n GET_UPGRADES_DOWNGRADES = \"get_upgrades_downgrades\"\n GET_EARNINGS = \"get_earnings\"\n GET_INCOME_STMT = \"get_income_stmt\"\n\n\nclass YahooFinanceSchema(BaseModel):\n symbol: str = Field(..., description=\"The stock symbol to retrieve data for.\")\n method: YahooFinanceMethod = Field(YahooFinanceMethod.GET_INFO, description=\"The type of data to retrieve.\")\n num_news: int | None = Field(5, description=\"The number of news articles to retrieve.\")\n\n\nclass YfinanceToolComponent(LCToolComponent):\n display_name = \"Yahoo Finance\"\n description = \"\"\"Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) \\\nto access financial data and market information from Yahoo Finance.\"\"\"\n icon = \"trending-up\"\n name = \"YahooFinanceTool\"\n\n inputs = [\n MessageTextInput(\n name=\"symbol\",\n display_name=\"Stock Symbol\",\n info=\"The stock symbol to retrieve data for (e.g., AAPL, GOOG).\",\n ),\n DropdownInput(\n name=\"method\",\n display_name=\"Data Method\",\n info=\"The type of data to retrieve.\",\n options=list(YahooFinanceMethod),\n value=\"get_news\",\n ),\n IntInput(\n name=\"num_news\",\n display_name=\"Number of News\",\n info=\"The number of news articles to retrieve (only applicable for get_news).\",\n value=5,\n ),\n ]\n\n def run_model(self) -> list[Data]:\n return self._yahoo_finance_tool(\n self.symbol,\n self.method,\n self.num_news,\n )\n\n def build_tool(self) -> Tool:\n return StructuredTool.from_function(\n name=\"yahoo_finance\",\n description=\"Access financial data and market information from Yahoo Finance.\",\n func=self._yahoo_finance_tool,\n args_schema=YahooFinanceSchema,\n )\n\n def _yahoo_finance_tool(\n self,\n symbol: str,\n method: YahooFinanceMethod,\n num_news: int | None = 5,\n ) -> list[Data]:\n ticker = yf.Ticker(symbol)\n\n try:\n if method == YahooFinanceMethod.GET_INFO:\n result = ticker.info\n elif method == YahooFinanceMethod.GET_NEWS:\n result = ticker.news[:num_news]\n else:\n result = getattr(ticker, method.value)()\n\n result = pprint.pformat(result)\n\n if method == YahooFinanceMethod.GET_NEWS:\n data_list = [Data(data=article) for article in ast.literal_eval(result)]\n else:\n data_list = [Data(data={\"result\": result})]\n\n except Exception as e:\n error_message = f\"Error retrieving data: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n return data_list\n"
},
"method": {
"_input_type": "DropdownInput",
"advanced": false,
"combobox": false,
"display_name": "Data Method",
"dynamic": false,
"info": "The type of data to retrieve.",
"name": "method",
"options": [
"get_info",
"get_news",
"get_actions",
"get_analysis",
"get_balance_sheet",
"get_calendar",
"get_cashflow",
"get_institutional_holders",
"get_recommendations",
"get_sustainability",
"get_major_holders",
"get_mutualfund_holders",
"get_insider_purchases",
"get_insider_transactions",
"get_insider_roster_holders",
"get_dividends",
"get_capital_gains",
"get_splits",
"get_shares",
"get_fast_info",
"get_sec_filings",
"get_recommendations_summary",
"get_upgrades_downgrades",
"get_earnings",
"get_income_stmt"
],
"placeholder": "",
"required": false,
"show": true,
"title_case": false,
"tool_mode": false,
"trace_as_metadata": true,
"type": "str",
"value": "get_news"
},
"num_news": {
"_input_type": "IntInput",
"advanced": false,
"display_name": "Number of News",
"dynamic": false,
"info": "The number of news articles to retrieve (only applicable for get_news).",
"list": false,
"name": "num_news",
"placeholder": "",
"required": false,
"show": true,
"title_case": false,
"trace_as_metadata": true,
"type": "int",
"value": 5
},
"symbol": {
"_input_type": "MessageTextInput",
"advanced": false,
"display_name": "Stock Symbol",
"dynamic": false,
"info": "The stock symbol to retrieve data for (e.g., AAPL, GOOG).",
"input_types": [
"Message"
],
"list": false,
"load_from_db": false,
"name": "symbol",
"placeholder": "",
"required": false,
"show": true,
"title_case": false,
"tool_mode": false,
"trace_as_input": true,
"trace_as_metadata": true,
"type": "str",
"value": "NVDA"
}
},
"tool_mode": false
},
"type": "YahooFinanceTool"
},
"dragging": false,
"height": 475,
"id": "YahooFinanceTool-PzHUy",
"position": {
"x": 1905.5096784216487,
"y": 313.6052678310467
},
"positionAbsolute": {
"x": 1905.5096784216487,
"y": 313.6052678310467
},
"selected": false,
"type": "genericNode",
"width": 320
},
{
"data": {
"id": "ChatInput-dBek4",
"id": "ChatInput-sTYr3",
"node": {
"base_classes": [
"Message"
@ -903,7 +760,7 @@
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.0.19.post2",
"lf_version": "1.1.0.dev4",
"metadata": {},
"output_types": [],
"outputs": [
@ -1047,7 +904,7 @@
"trace_as_input": true,
"trace_as_metadata": true,
"type": "str",
"value": "search news about AAPL"
"value": ""
},
"sender": {
"_input_type": "DropdownInput",
@ -1159,14 +1016,14 @@
},
"dragging": false,
"height": 234,
"id": "ChatInput-dBek4",
"id": "ChatInput-sTYr3",
"position": {
"x": 1907.4497817799925,
"y": 817.955066634514
"x": 1939.9269765193949,
"y": 965.3667152408464
},
"positionAbsolute": {
"x": 1907.4497817799925,
"y": 817.955066634514
"x": 1939.9269765193949,
"y": 965.3667152408464
},
"selected": false,
"type": "genericNode",
@ -1176,7 +1033,7 @@
"data": {
"description": "Display a chat message in the Playground.",
"display_name": "Chat Output",
"id": "ChatOutput-ULcvr",
"id": "ChatOutput-Tkzec",
"node": {
"base_classes": [
"Message"
@ -1202,6 +1059,7 @@
"frozen": false,
"icon": "MessagesSquare",
"legacy": false,
"lf_version": "1.1.0.dev4",
"metadata": {},
"output_types": [],
"outputs": [
@ -1435,7 +1293,7 @@
},
"dragging": false,
"height": 234,
"id": "ChatOutput-ULcvr",
"id": "ChatOutput-Tkzec",
"position": {
"x": 2683.9938458383212,
"y": 556.5828467235146
@ -1450,49 +1308,319 @@
},
{
"data": {
"id": "note-FSVUJ",
"id": "URL-FOPyh",
"node": {
"description": "# Simple Agent\nA straightforward implementation of a chatbot focusing on processing inputs and generating responses employing conversation memory capabilities.\n## Core Components\n1. **Chat Input**\n - Collects user messages for processing.\n2. **Agent**\n - Analyzes user input.\n - Generates contextually relevant responses.\n - Utilizes tools to refine and enhance replies as needed.\n3. **Chat Output**\n - Presents formatted responses to the user.\n - Ensures consistent conversational flow.\n## Features\n- Processes each message independently.\n- Focuses on generating relevant, immediate responses.\n- Handles each chat interaction as a standalone session.\n## Quick Start\n1. Initiate a chat by sending a message in Chat Input.\n2. The Agent processes the message, considering any immediate context.\n3. Receive a response in Chat Output.\n\nThis simple agent chatbot provides a streamlined conversational flow without the complexity of managing conversation memory.",
"base_classes": [
"Data",
"Message"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
"description": "Fetch content from one or more URLs.",
"display_name": "URL",
"documentation": "",
"edited": false,
"field_order": [
"urls",
"format"
],
"frozen": false,
"icon": "layout-template",
"legacy": false,
"lf_version": "1.1.0.dev4",
"metadata": {},
"output_types": [],
"outputs": [
{
"cache": true,
"display_name": "Toolset",
"hidden": null,
"method": "to_toolkit",
"name": "component_as_tool",
"required_inputs": null,
"selected": "Tool",
"types": [
"Tool"
],
"value": "__UNDEFINED__"
}
],
"pinned": false,
"template": {
"_type": "Component",
"code": {
"advanced": true,
"dynamic": true,
"fileTypes": [],
"file_path": "",
"info": "",
"list": false,
"load_from_db": false,
"multiline": true,
"name": "code",
"password": false,
"placeholder": "",
"required": true,
"show": true,
"title_case": false,
"type": "code",
"value": "import re\n\nfrom langchain_community.document_loaders import AsyncHtmlLoader, WebBaseLoader\n\nfrom langflow.custom import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema import Data\nfrom langflow.schema.message import Message\n\n\nclass URLComponent(Component):\n display_name = \"URL\"\n description = \"Fetch content from one or more URLs.\"\n icon = \"layout-template\"\n name = \"URL\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs, by clicking the '+' button.\",\n is_list=True,\n tool_mode=True,\n ),\n DropdownInput(\n name=\"format\",\n display_name=\"Output Format\",\n info=\"Output Format. Use 'Text' to extract the text from the HTML or 'Raw HTML' for the raw HTML content.\",\n options=[\"Text\", \"Raw HTML\"],\n value=\"Text\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"fetch_content\"),\n Output(display_name=\"Text\", name=\"text\", method=\"fetch_content_text\"),\n ]\n\n def ensure_url(self, string: str) -> str:\n \"\"\"Ensures the given string is a URL by adding 'http://' if it doesn't start with 'http://' or 'https://'.\n\n Raises an error if the string is not a valid URL.\n\n Parameters:\n string (str): The string to be checked and possibly modified.\n\n Returns:\n str: The modified string that is ensured to be a URL.\n\n Raises:\n ValueError: If the string is not a valid URL.\n \"\"\"\n if not string.startswith((\"http://\", \"https://\")):\n string = \"http://\" + string\n\n # Basic URL validation regex\n url_regex = re.compile(\n r\"^(https?:\\/\\/)?\" # optional protocol\n r\"(www\\.)?\" # optional www\n r\"([a-zA-Z0-9.-]+)\" # domain\n r\"(\\.[a-zA-Z]{2,})?\" # top-level domain\n r\"(:\\d+)?\" # optional port\n r\"(\\/[^\\s]*)?$\", # optional path\n re.IGNORECASE,\n )\n\n if not url_regex.match(string):\n msg = f\"Invalid URL: {string}\"\n raise ValueError(msg)\n\n return string\n\n def fetch_content(self) -> list[Data]:\n urls = [self.ensure_url(url.strip()) for url in self.urls if url.strip()]\n if self.format == \"Raw HTML\":\n loader = AsyncHtmlLoader(web_path=urls, encoding=\"utf-8\")\n else:\n loader = WebBaseLoader(web_paths=urls, encoding=\"utf-8\")\n docs = loader.load()\n data = [Data(text=doc.page_content, **doc.metadata) for doc in docs]\n self.status = data\n return data\n\n def fetch_content_text(self) -> Message:\n data = self.fetch_content()\n\n result_string = data_to_text(\"{text}\", data)\n self.status = result_string\n return Message(text=result_string)\n"
},
"format": {
"_input_type": "DropdownInput",
"advanced": false,
"combobox": false,
"display_name": "Output Format",
"dynamic": false,
"info": "Output Format. Use 'Text' to extract the text from the HTML or 'Raw HTML' for the raw HTML content.",
"name": "format",
"options": [
"Text",
"Raw HTML"
],
"placeholder": "",
"required": false,
"show": true,
"title_case": false,
"tool_mode": false,
"trace_as_metadata": true,
"type": "str",
"value": "Text"
},
"urls": {
"_input_type": "MessageTextInput",
"advanced": false,
"display_name": "URLs",
"dynamic": false,
"info": "Enter one or more URLs, by clicking the '+' button.",
"input_types": [
"Message"
],
"list": true,
"load_from_db": false,
"name": "urls",
"placeholder": "",
"required": false,
"show": true,
"title_case": false,
"tool_mode": true,
"trace_as_input": true,
"trace_as_metadata": true,
"type": "str",
"value": ""
}
},
"tool_mode": false
},
"type": "URL"
},
"dragging": false,
"height": 320,
"id": "URL-FOPyh",
"position": {
"x": 1942.4405475324484,
"y": 274.6204436838327
},
"positionAbsolute": {
"x": 1942.4405475324484,
"y": 274.6204436838327
},
"selected": false,
"type": "genericNode",
"width": 320
},
{
"data": {
"id": "CalculatorTool-IfWT1",
"node": {
"base_classes": [
"Data",
"Tool"
],
"beta": false,
"conditional_paths": [],
"custom_fields": {},
"description": "Perform basic arithmetic operations on a given expression.",
"display_name": "Calculator",
"documentation": "",
"edited": false,
"field_order": [
"expression"
],
"frozen": false,
"icon": "calculator",
"legacy": false,
"lf_version": "1.1.0.dev4",
"metadata": {},
"output_types": [],
"outputs": [
{
"cache": true,
"display_name": "Data",
"method": "run_model",
"name": "api_run_model",
"required_inputs": [],
"selected": "Data",
"types": [
"Data"
],
"value": "__UNDEFINED__"
},
{
"cache": true,
"display_name": "Tool",
"method": "build_tool",
"name": "api_build_tool",
"required_inputs": [],
"selected": "Tool",
"types": [
"Tool"
],
"value": "__UNDEFINED__"
}
],
"pinned": false,
"template": {
"_type": "Component",
"code": {
"advanced": true,
"dynamic": true,
"fileTypes": [],
"file_path": "",
"info": "",
"list": false,
"load_from_db": false,
"multiline": true,
"name": "code",
"password": false,
"placeholder": "",
"required": true,
"show": true,
"title_case": false,
"type": "code",
"value": "import ast\nimport operator\n\nfrom langchain.tools import StructuredTool\nfrom langchain_core.tools import ToolException\nfrom loguru import logger\nfrom pydantic import BaseModel, Field\n\nfrom langflow.base.langchain_utilities.model import LCToolComponent\nfrom langflow.field_typing import Tool\nfrom langflow.inputs import MessageTextInput\nfrom langflow.schema import Data\n\n\nclass CalculatorToolComponent(LCToolComponent):\n display_name = \"Calculator\"\n description = \"Perform basic arithmetic operations on a given expression.\"\n icon = \"calculator\"\n name = \"CalculatorTool\"\n\n inputs = [\n MessageTextInput(\n name=\"expression\",\n display_name=\"Expression\",\n info=\"The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').\",\n ),\n ]\n\n class CalculatorToolSchema(BaseModel):\n expression: str = Field(..., description=\"The arithmetic expression to evaluate.\")\n\n def run_model(self) -> list[Data]:\n return self._evaluate_expression(self.expression)\n\n def build_tool(self) -> Tool:\n return StructuredTool.from_function(\n name=\"calculator\",\n description=\"Evaluate basic arithmetic expressions. Input should be a string containing the expression.\",\n func=self._eval_expr_with_error,\n args_schema=self.CalculatorToolSchema,\n )\n\n def _eval_expr(self, node):\n # Define the allowed operators\n operators = {\n ast.Add: operator.add,\n ast.Sub: operator.sub,\n ast.Mult: operator.mul,\n ast.Div: operator.truediv,\n ast.Pow: operator.pow,\n }\n if isinstance(node, ast.Num):\n return node.n\n if isinstance(node, ast.BinOp):\n return operators[type(node.op)](self._eval_expr(node.left), self._eval_expr(node.right))\n if isinstance(node, ast.UnaryOp):\n return operators[type(node.op)](self._eval_expr(node.operand))\n if isinstance(node, ast.Call):\n msg = (\n \"Function calls like sqrt(), sin(), cos() etc. are not supported. \"\n \"Only basic arithmetic operations (+, -, *, /, **) are allowed.\"\n )\n raise TypeError(msg)\n msg = f\"Unsupported operation or expression type: {type(node).__name__}\"\n raise TypeError(msg)\n\n def _eval_expr_with_error(self, expression: str) -> list[Data]:\n try:\n return self._evaluate_expression(expression)\n except Exception as e:\n raise ToolException(str(e)) from e\n\n def _evaluate_expression(self, expression: str) -> list[Data]:\n try:\n # Parse the expression and evaluate it\n tree = ast.parse(expression, mode=\"eval\")\n result = self._eval_expr(tree.body)\n\n # Format the result to a reasonable number of decimal places\n formatted_result = f\"{result:.6f}\".rstrip(\"0\").rstrip(\".\")\n\n self.status = formatted_result\n return [Data(data={\"result\": formatted_result})]\n\n except (SyntaxError, TypeError, KeyError) as e:\n error_message = f\"Invalid expression: {e}\"\n self.status = error_message\n return [Data(data={\"error\": error_message, \"input\": expression})]\n except ZeroDivisionError:\n error_message = \"Error: Division by zero\"\n self.status = error_message\n return [Data(data={\"error\": error_message, \"input\": expression})]\n except Exception as e: # noqa: BLE001\n logger.opt(exception=True).debug(\"Error evaluating expression\")\n error_message = f\"Error: {e}\"\n self.status = error_message\n return [Data(data={\"error\": error_message, \"input\": expression})]\n"
},
"expression": {
"_input_type": "MessageTextInput",
"advanced": false,
"display_name": "Expression",
"dynamic": false,
"info": "The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').",
"input_types": [
"Message"
],
"list": false,
"load_from_db": false,
"name": "expression",
"placeholder": "",
"required": false,
"show": true,
"title_case": false,
"tool_mode": true,
"trace_as_input": true,
"trace_as_metadata": true,
"type": "str",
"value": ""
}
},
"tool_mode": false
},
"type": "CalculatorTool"
},
"dragging": false,
"height": 302,
"id": "CalculatorTool-IfWT1",
"position": {
"x": 1938.2271796804105,
"y": 629.2915039696703
},
"positionAbsolute": {
"x": 1938.2271796804105,
"y": 629.2915039696703
},
"selected": false,
"type": "genericNode",
"width": 320
},
{
"data": {
"id": "note-QuJAF",
"node": {
"description": "# 📖 README\nRun an Agent with URL and Calculator tools available for its use. \nThe Agent decides which tool to use to solve a problem.\n## Quick start\n\n1. Add your OpenAI API key to the Agent.\n2. Open the Playground and chat with the Agent. Request some information about a recipe, and then ask to add two numbers together. In the responses, the Agent will use different tools to solve different problems.\n\n## Next steps\nConnect more tools to the Agent to create your perfect assistant.\n\nFor more, see the [Langflow docs](https://docs.langflow.org/agents-tool-calling-agent-component).",
"display_name": "",
"documentation": "",
"template": {}
"template": {
"backgroundColor": "neutral"
}
},
"type": "note"
},
"dragging": false,
"height": 736,
"id": "note-FSVUJ",
"height": 571,
"id": "note-QuJAF",
"position": {
"x": 1512.8976594415833,
"y": 312.9558305744385
"x": 1314.267618793912,
"y": 323.12512509078374
},
"positionAbsolute": {
"x": 1512.8976594415833,
"y": 312.9558305744385
"x": 1314.267618793912,
"y": 323.12512509078374
},
"resizing": false,
"selected": false,
"style": {
"height": 736,
"width": 382
"height": 571,
"width": 600
},
"type": "noteNode",
"width": 382
"width": 600
},
{
"data": {
"id": "note-uxxuk",
"node": {
"description": "### 💡 Add your OpenAI API key here👇",
"display_name": "",
"documentation": "",
"template": {
"backgroundColor": "transparent"
}
},
"type": "note"
},
"dragging": false,
"height": 324,
"id": "note-uxxuk",
"position": {
"x": 2302.9552933034743,
"y": 288.4851054994825
},
"positionAbsolute": {
"x": 2302.9552933034743,
"y": 288.4851054994825
},
"resizing": false,
"selected": false,
"style": {
"height": 324,
"width": 330
},
"type": "noteNode",
"width": 330
}
],
"viewport": {
"x": -1275.792144730309,
"y": -144.09980323772618,
"zoom": 0.8828160439097184
"x": -813.150138361608,
"y": -64.1501688971494,
"zoom": 0.6612152367588026
}
},
"description": "Get started with an agent that calls the Yahoo Finance tool for quick access to stock prices, market trends, and financial data.",
"description": "A simple but powerful starter agent.",
"endpoint_name": null,
"gradient": "5",
"icon": "Bot",
"id": "a774332d-6fb5-43b6-96a4-d3eb8e62ddc0",
"id": "263070d6-3560-4f4d-a6c4-003f4a586e6e",
"is_component": false,
"last_tested_version": "1.0.19.post2",
"last_tested_version": "1.1.0",
"name": "Simple Agent",
"tags": [
"assistants",

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -93,6 +93,6 @@ test("Simple Agent", async ({ page }) => {
const concatAllText = textContents.join(" ").toLowerCase();
expect(concatAllText).toContain("apple");
expect(concatAllText.length).toBeGreaterThan(100);
expect(concatAllText).toContain("hello! how can i assist you today?");
expect(concatAllText.length).toBeGreaterThan(20);
});

View file

@ -112,7 +112,6 @@ const templateIds = [
"template_travel-planning-agents",
"template_research-agent",
"template_simple-agent",
"template_youtube-transcript-q&a",
"template_sequential-tasks-agents",
"template_market-research",
];