From 5b5f1ddac528ca22a1893ab457ba1c48d8117033 Mon Sep 17 00:00:00 2001 From: Yuqi Tang Date: Tue, 24 Jun 2025 10:36:26 -0700 Subject: [PATCH] fix: Clean up some more base templates (#8708) * fix: Clean up some more base templates * update simple agent and research translation loop * update travel planning agent * update * change outpu * update translation loop --------- Co-authored-by: Eric Hare --- .../base/langflow/initial_setup/setup.py | 1 + .../starter_projects/Document Q&A.json | 1426 ++++++------ .../starter_projects/Memory Chatbot.json | 467 +--- .../Research Translation Loop.json | 288 ++- .../starter_projects/Simple Agent.json | 1078 +++++---- .../starter_projects/Social Media Agent.json | 216 +- .../Travel Planning Agents.json | 2036 ++++++++--------- 7 files changed, 2540 insertions(+), 2972 deletions(-) diff --git a/src/backend/base/langflow/initial_setup/setup.py b/src/backend/base/langflow/initial_setup/setup.py index 5ba8675f6..9503ba5b5 100644 --- a/src/backend/base/langflow/initial_setup/setup.py +++ b/src/backend/base/langflow/initial_setup/setup.py @@ -73,6 +73,7 @@ def update_projects_components_with_latest_component_versions(project_data, all_ is_tool_or_agent = node_data.get("tool_mode", False) or node_data.get("key") in { "Agent", "LanguageModelComponent", + "TypeConverterComponent", } has_tool_outputs = any(output.get("types") == ["Tool"] for output in node_data.get("outputs", [])) if "outputs" in latest_node and not has_tool_outputs and not is_tool_or_agent: diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json b/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json index 25487f833..9944b070c 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json @@ -1,13 +1,42 @@ { "data": { "edges": [ + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "parser", + "id": "parser-1O59j", + "name": "parsed_text", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "Document", + "id": "Prompt-GjFNQ", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "reactflow__edge-parser-1O59j{œdataTypeœ:œparserœ,œidœ:œparser-1O59jœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-GjFNQ{œfieldNameœ:œDocumentœ,œidœ:œPrompt-GjFNQœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "parser-1O59j", + "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-1O59jœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-GjFNQ", + "targetHandle": "{œfieldNameœ: œDocumentœ, œidœ: œPrompt-GjFNQœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, { "animated": false, "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-82ow1", + "id": "ChatInput-l9kmd", "name": "message", "output_types": [ "Message" @@ -15,19 +44,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "OpenAIModel-Xctjl", + "id": "LanguageModelComponent-IEakg", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-82ow1{œdataTypeœ:œChatInputœ,œidœ:œChatInput-82ow1œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-Xctjl{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-Xctjlœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__ChatInput-l9kmd{œdataTypeœ:œChatInputœ,œidœ:œChatInput-l9kmdœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-IEakg{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-IEakgœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-82ow1", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-82ow1œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-Xctjl", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-Xctjlœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-l9kmd", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-l9kmdœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-IEakg", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-IEakgœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -35,7 +64,7 @@ "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-yAr8f", + "id": "Prompt-GjFNQ", "name": "prompt", "output_types": [ "Message" @@ -43,27 +72,27 @@ }, "targetHandle": { "fieldName": "system_message", - "id": "OpenAIModel-Xctjl", + "id": "LanguageModelComponent-IEakg", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-yAr8f{œdataTypeœ:œPromptœ,œidœ:œPrompt-yAr8fœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-Xctjl{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-Xctjlœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__Prompt-GjFNQ{œdataTypeœ:œPromptœ,œidœ:œPrompt-GjFNQœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-IEakg{œfieldNameœ:œsystem_messageœ,œidœ:œLanguageModelComponent-IEakgœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-yAr8f", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-yAr8fœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-Xctjl", - "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-Xctjlœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-GjFNQ", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-GjFNQœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-IEakg", + "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œLanguageModelComponent-IEakgœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, "className": "", "data": { "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-Xctjl", + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-IEakg", "name": "text_output", "output_types": [ "Message" @@ -71,7 +100,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-hSEAB", + "id": "ChatOutput-FO9AH", "inputTypes": [ "Data", "DataFrame", @@ -80,19 +109,20 @@ "type": "str" } }, - "id": "reactflow__edge-OpenAIModel-Xctjl{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-Xctjlœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-hSEAB{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-hSEABœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__LanguageModelComponent-IEakg{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-IEakgœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-FO9AH{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-FO9AHœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "OpenAIModel-Xctjl", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-Xctjlœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-hSEAB", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-hSEABœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "LanguageModelComponent-IEakg", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-IEakgœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-FO9AH", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-FO9AHœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, + "className": "", "data": { "sourceHandle": { "dataType": "File", - "id": "File-3BeiJ", + "id": "File-cLJI5", "name": "dataframe", "output_types": [ "DataFrame" @@ -100,7 +130,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "parser-mO32W", + "id": "parser-1O59j", "inputTypes": [ "DataFrame", "Data" @@ -108,40 +138,12 @@ "type": "other" } }, - "id": "xy-edge__File-3BeiJ{œdataTypeœ:œFileœ,œidœ:œFile-3BeiJœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-parser-mO32W{œfieldNameœ:œinput_dataœ,œidœ:œparser-mO32Wœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", + "id": "xy-edge__File-cLJI5{œdataTypeœ:œFileœ,œidœ:œFile-cLJI5œ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-parser-1O59j{œfieldNameœ:œinput_dataœ,œidœ:œparser-1O59jœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", "selected": false, - "source": "File-3BeiJ", - "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-3BeiJœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", - "target": "parser-mO32W", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-mO32Wœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "data": { - "sourceHandle": { - "dataType": "parser", - "id": "parser-mO32W", - "name": "parsed_text", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "Document", - "id": "Prompt-yAr8f", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "xy-edge__parser-mO32W{œdataTypeœ:œparserœ,œidœ:œparser-mO32Wœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-yAr8f{œfieldNameœ:œDocumentœ,œidœ:œPrompt-yAr8fœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "selected": false, - "source": "parser-mO32W", - "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-mO32Wœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-yAr8f", - "targetHandle": "{œfieldNameœ: œDocumentœ, œidœ: œPrompt-yAr8fœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "source": "File-cLJI5", + "sourceHandle": "{œdataTypeœ: œFileœ, œidœ: œFile-cLJI5œ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", + "target": "parser-1O59j", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-1O59jœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" } ], "nodes": [ @@ -149,7 +151,7 @@ "data": { "description": "Get chat inputs from the Playground.", "display_name": "Chat Input", - "id": "ChatInput-82ow1", + "id": "ChatInput-l9kmd", "node": { "base_classes": [ "Message" @@ -172,7 +174,7 @@ "frozen": false, "icon": "MessagesSquare", "legacy": false, - "lf_version": "1.0.19.post2", + "lf_version": "1.4.3", "metadata": {}, "output_types": [], "outputs": [ @@ -412,12 +414,12 @@ } } }, - "type": "ChatInput", - "selected_output": "message" + "selected_output": "message", + "type": "ChatInput" }, "dragging": false, "height": 234, - "id": "ChatInput-82ow1", + "id": "ChatInput-l9kmd", "measured": { "height": 234, "width": 320 @@ -438,7 +440,7 @@ "data": { "description": "Display a chat message in the Playground.", "display_name": "Chat Output", - "id": "ChatOutput-hSEAB", + "id": "ChatOutput-FO9AH", "node": { "base_classes": [ "Message" @@ -464,7 +466,7 @@ "frozen": false, "icon": "MessagesSquare", "legacy": false, - "lf_version": "1.0.19.post2", + "lf_version": "1.4.3", "metadata": {}, "output_types": [], "outputs": [ @@ -721,7 +723,7 @@ }, "dragging": false, "height": 234, - "id": "ChatOutput-hSEAB", + "id": "ChatOutput-FO9AH", "measured": { "height": 234, "width": 320 @@ -740,7 +742,7 @@ }, { "data": { - "id": "note-7pTJx", + "id": "note-CTOUn", "node": { "description": "# Document Q&A\n\nThis flow loads a file and uses an LLM to answer questions based on content from the loaded document. \n\n## Prerequisites\n\n* An [OpenAI API key](https://platform.openai.com/)\n\n## Quickstart\n\n1. Paste your OpenAI API key in the **OpenAI** model component.\n2. In the **File** component, select a file you want to load.\n3. Open the **Playground** and chat with your document.", "display_name": "", @@ -751,10 +753,10 @@ }, "dragging": false, "height": 509, - "id": "note-7pTJx", + "id": "note-CTOUn", "measured": { "height": 509, - "width": 421 + "width": 420 }, "position": { "x": -306.48794920240215, @@ -773,290 +775,11 @@ "type": "noteNode", "width": 420 }, - { - "data": { - "id": "File-3BeiJ", - "node": { - "base_classes": [ - "Data" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Loads content from one or more files as a DataFrame.", - "display_name": "File", - "documentation": "", - "edited": false, - "field_order": [ - "path", - "silent_errors", - "use_multithreading", - "concurrency_multithreading" - ], - "frozen": false, - "icon": "file-text", - "legacy": false, - "lf_version": "1.2.0", - "metadata": {}, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Loaded Files", - "group_outputs": false, - "method": "load_files", - "name": "dataframe", - "selected": "DataFrame", - "tool_mode": true, - "types": [ - "DataFrame" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Raw Content", - "group_outputs": false, - "method": "load_files_message", - "name": "message", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "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": "from langflow.base.data.base_file import BaseFileComponent\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parallel_load_data, parse_text_file_to_data\nfrom langflow.io import BoolInput, IntInput\nfrom langflow.schema.data import Data\n\n\nclass FileComponent(BaseFileComponent):\n \"\"\"Handles loading and processing of individual or zipped text files.\n\n This component supports processing multiple valid files within a zip archive,\n resolving paths, validating file types, and optionally using multithreading for processing.\n \"\"\"\n\n display_name = \"File\"\n description = \"Loads content from one or more files as a DataFrame.\"\n icon = \"file-text\"\n name = \"File\"\n\n VALID_EXTENSIONS = TEXT_FILE_TYPES\n\n inputs = [\n *BaseFileComponent._base_inputs,\n BoolInput(\n name=\"use_multithreading\",\n display_name=\"[Deprecated] Use Multithreading\",\n advanced=True,\n value=True,\n info=\"Set 'Processing Concurrency' greater than 1 to enable multithreading.\",\n ),\n IntInput(\n name=\"concurrency_multithreading\",\n display_name=\"Processing Concurrency\",\n advanced=True,\n info=\"When multiple files are being processed, the number of files to process concurrently.\",\n value=1,\n ),\n ]\n\n outputs = [\n *BaseFileComponent._base_outputs,\n ]\n\n def process_files(self, file_list: list[BaseFileComponent.BaseFile]) -> list[BaseFileComponent.BaseFile]:\n \"\"\"Processes files either sequentially or in parallel, depending on concurrency settings.\n\n Args:\n file_list (list[BaseFileComponent.BaseFile]): List of files to process.\n\n Returns:\n list[BaseFileComponent.BaseFile]: Updated list of files with merged data.\n \"\"\"\n\n def process_file(file_path: str, *, silent_errors: bool = False) -> Data | None:\n \"\"\"Processes a single file and returns its Data object.\"\"\"\n try:\n return parse_text_file_to_data(file_path, silent_errors=silent_errors)\n except FileNotFoundError as e:\n msg = f\"File not found: {file_path}. Error: {e}\"\n self.log(msg)\n if not silent_errors:\n raise\n return None\n except Exception as e:\n msg = f\"Unexpected error processing {file_path}: {e}\"\n self.log(msg)\n if not silent_errors:\n raise\n return None\n\n if not file_list:\n msg = \"No files to process.\"\n raise ValueError(msg)\n\n concurrency = 1 if not self.use_multithreading else max(1, self.concurrency_multithreading)\n file_count = len(file_list)\n\n parallel_processing_threshold = 2\n if concurrency < parallel_processing_threshold or file_count < parallel_processing_threshold:\n if file_count > 1:\n self.log(f\"Processing {file_count} files sequentially.\")\n processed_data = [process_file(str(file.path), silent_errors=self.silent_errors) for file in file_list]\n else:\n self.log(f\"Starting parallel processing of {file_count} files with concurrency: {concurrency}.\")\n file_paths = [str(file.path) for file in file_list]\n processed_data = parallel_load_data(\n file_paths,\n silent_errors=self.silent_errors,\n load_function=process_file,\n max_concurrency=concurrency,\n )\n\n # Use rollup_basefile_data to merge processed data with BaseFile objects\n return self.rollup_data(file_list, processed_data)\n" - }, - "concurrency_multithreading": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Processing Concurrency", - "dynamic": false, - "info": "When multiple files are being processed, the number of files to process concurrently.", - "list": false, - "name": "concurrency_multithreading", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 4 - }, - "delete_server_file_after_processing": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Delete Server File After Processing", - "dynamic": false, - "info": "If true, the Server File Path will be deleted after processing.", - "list": false, - "name": "delete_server_file_after_processing", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "file_path": { - "_input_type": "HandleInput", - "advanced": true, - "display_name": "Server File Path", - "dynamic": false, - "info": "Data object with a 'file_path' property pointing to server file or a Message object with a path to the file. Supercedes 'Path' but supports same file types.", - "input_types": [ - "Data", - "Message" - ], - "list": true, - "name": "file_path", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "ignore_unspecified_files": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Ignore Unspecified Files", - "dynamic": false, - "info": "If true, Data with no 'file_path' property will be ignored.", - "list": false, - "name": "ignore_unspecified_files", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "ignore_unsupported_extensions": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Ignore Unsupported Extensions", - "dynamic": false, - "info": "If true, files with unsupported extensions will not be processed.", - "list": false, - "name": "ignore_unsupported_extensions", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "path": { - "_input_type": "FileInput", - "advanced": false, - "display_name": "Files", - "dynamic": false, - "fileTypes": [ - "txt", - "md", - "mdx", - "csv", - "json", - "yaml", - "yml", - "xml", - "html", - "htm", - "pdf", - "docx", - "py", - "sh", - "sql", - "js", - "ts", - "tsx", - "zip", - "tar", - "tgz", - "bz2", - "gz" - ], - "file_path": [], - "info": "Supported file extensions: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx; optionally bundled in file extensions: zip, tar, tgz, bz2, gz", - "list": true, - "name": "path", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "file", - "value": "" - }, - "separator": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "Separator", - "dynamic": false, - "info": "Specify the separator to use between multiple outputs in Message format.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "separator", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "\n\n" - }, - "silent_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Silent Errors", - "dynamic": false, - "info": "If true, errors will not raise an exception.", - "list": false, - "name": "silent_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "use_multithreading": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "[Deprecated] Use Multithreading", - "dynamic": false, - "info": "Set 'Processing Concurrency' greater than 1 to enable multithreading.", - "list": false, - "name": "use_multithreading", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - } - }, - "tool_mode": false - }, - "type": "File", - "selected_output": "dataframe" - }, - "dragging": false, - "height": 232, - "id": "File-3BeiJ", - "measured": { - "height": 232, - "width": 320 - }, - "position": { - "x": 150.6029945346864, - "y": -88.71582365936283 - }, - "positionAbsolute": { - "x": 155.39382083637838, - "y": -82.32805525710685 - }, - "selected": false, - "type": "genericNode", - "width": 320 - }, { "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-yAr8f", + "id": "Prompt-GjFNQ", "node": { "base_classes": [ "Message" @@ -1083,7 +806,7 @@ "is_input": null, "is_output": null, "legacy": false, - "lf_version": "1.0.19.post2", + "lf_version": "1.4.3", "metadata": {}, "name": "", "output_types": [], @@ -1188,12 +911,12 @@ }, "tool_mode": false }, - "type": "Prompt", - "selected_output": "prompt" + "selected_output": "prompt", + "type": "Prompt" }, "dragging": false, "height": 347, - "id": "Prompt-yAr8f", + "id": "Prompt-GjFNQ", "measured": { "height": 347, "width": 320 @@ -1212,397 +935,7 @@ }, { "data": { - "id": "OpenAIModel-Xctjl", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "category": "models", - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "key": "OpenAIModel", - "legacy": false, - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 0.14285714285714285, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "OPENAI_API_KEY" - }, - "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": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - } - }, - "tool_mode": false - }, - "showNode": true, - "type": "OpenAIModel", - "selected_output": "text_output" - }, - "dragging": false, - "id": "OpenAIModel-Xctjl", - "measured": { - "height": 525, - "width": 320 - }, - "position": { - "x": 1257.1422612381514, - "y": -99.92567023810267 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "parser-mO32W", + "id": "parser-1O59j", "node": { "base_classes": [ "Message" @@ -1625,6 +958,7 @@ "icon": "braces", "key": "parser", "legacy": false, + "lf_version": "1.4.3", "metadata": {}, "minimized": false, "output_types": [], @@ -1758,35 +1092,623 @@ }, "tool_mode": false }, + "selected_output": "parsed_text", "showNode": true, - "type": "parser", - "selected_output": "parsed_text" + "type": "parser" }, "dragging": false, - "id": "parser-mO32W", + "id": "parser-1O59j", "measured": { - "height": 395, + "height": 360, "width": 320 }, "position": { "x": 517.4341822104063, "y": -211.09448665229442 }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-IEakg", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Runs a language model given a specified provider. ", + "display_name": "Language Model", + "documentation": "", + "edited": false, + "field_order": [ + "provider", + "model_name", + "api_key", + "input_value", + "system_message", + "stream", + "temperature" + ], + "frozen": false, + "icon": "brain-circuit", + "legacy": false, + "lf_version": "1.4.3", + "metadata": { + "keywords": [ + "model", + "llm", + "language model", + "large language model" + ] + }, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Model Response", + "group_outputs": false, + "method": "text_response", + "name": "text_output", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "allows_loop": false, + "cache": true, + "display_name": "Language Model", + "group_outputs": false, + "method": "build_model", + "name": "model_output", + "options": null, + "required_inputs": null, + "selected": "LanguageModel", + "tool_mode": true, + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "priority": 0, + "template": { + "_type": "Component", + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "Model Provider API key", + "input_types": [], + "load_from_db": true, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "OPENAI_API_KEY" + }, + "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": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "System Message", + "dynamic": false, + "info": "A system message that helps set the behavior of the assistant", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "Controls randomness in responses", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + } + }, + "tool_mode": false + }, + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-IEakg", + "measured": { + "height": 532, + "width": 320 + }, + "position": { + "x": 1256.4027532477426, + "y": -116.62150897037591 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "File-cLJI5", + "node": { + "base_classes": [ + "DataFrame", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Loads content from one or more files as a DataFrame.", + "display_name": "File", + "documentation": "", + "edited": false, + "field_order": [ + "path", + "file_path", + "separator", + "silent_errors", + "delete_server_file_after_processing", + "ignore_unsupported_extensions", + "ignore_unspecified_files", + "use_multithreading", + "concurrency_multithreading" + ], + "frozen": false, + "icon": "file-text", + "legacy": false, + "lf_version": "1.4.3", + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Loaded Files", + "group_outputs": false, + "method": "load_files", + "name": "dataframe", + "selected": "DataFrame", + "tool_mode": true, + "types": [ + "DataFrame" + ], + "value": "__UNDEFINED__" + }, + { + "allows_loop": false, + "cache": true, + "display_name": "Raw Content", + "group_outputs": false, + "method": "load_files_message", + "name": "message", + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "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": "from langflow.base.data.base_file import BaseFileComponent\nfrom langflow.base.data.utils import TEXT_FILE_TYPES, parallel_load_data, parse_text_file_to_data\nfrom langflow.io import BoolInput, IntInput\nfrom langflow.schema.data import Data\n\n\nclass FileComponent(BaseFileComponent):\n \"\"\"Handles loading and processing of individual or zipped text files.\n\n This component supports processing multiple valid files within a zip archive,\n resolving paths, validating file types, and optionally using multithreading for processing.\n \"\"\"\n\n display_name = \"File\"\n description = \"Loads content from one or more files as a DataFrame.\"\n icon = \"file-text\"\n name = \"File\"\n\n VALID_EXTENSIONS = TEXT_FILE_TYPES\n\n inputs = [\n *BaseFileComponent._base_inputs,\n BoolInput(\n name=\"use_multithreading\",\n display_name=\"[Deprecated] Use Multithreading\",\n advanced=True,\n value=True,\n info=\"Set 'Processing Concurrency' greater than 1 to enable multithreading.\",\n ),\n IntInput(\n name=\"concurrency_multithreading\",\n display_name=\"Processing Concurrency\",\n advanced=True,\n info=\"When multiple files are being processed, the number of files to process concurrently.\",\n value=1,\n ),\n ]\n\n outputs = [\n *BaseFileComponent._base_outputs,\n ]\n\n def process_files(self, file_list: list[BaseFileComponent.BaseFile]) -> list[BaseFileComponent.BaseFile]:\n \"\"\"Processes files either sequentially or in parallel, depending on concurrency settings.\n\n Args:\n file_list (list[BaseFileComponent.BaseFile]): List of files to process.\n\n Returns:\n list[BaseFileComponent.BaseFile]: Updated list of files with merged data.\n \"\"\"\n\n def process_file(file_path: str, *, silent_errors: bool = False) -> Data | None:\n \"\"\"Processes a single file and returns its Data object.\"\"\"\n try:\n return parse_text_file_to_data(file_path, silent_errors=silent_errors)\n except FileNotFoundError as e:\n msg = f\"File not found: {file_path}. Error: {e}\"\n self.log(msg)\n if not silent_errors:\n raise\n return None\n except Exception as e:\n msg = f\"Unexpected error processing {file_path}: {e}\"\n self.log(msg)\n if not silent_errors:\n raise\n return None\n\n if not file_list:\n msg = \"No files to process.\"\n raise ValueError(msg)\n\n concurrency = 1 if not self.use_multithreading else max(1, self.concurrency_multithreading)\n file_count = len(file_list)\n\n parallel_processing_threshold = 2\n if concurrency < parallel_processing_threshold or file_count < parallel_processing_threshold:\n if file_count > 1:\n self.log(f\"Processing {file_count} files sequentially.\")\n processed_data = [process_file(str(file.path), silent_errors=self.silent_errors) for file in file_list]\n else:\n self.log(f\"Starting parallel processing of {file_count} files with concurrency: {concurrency}.\")\n file_paths = [str(file.path) for file in file_list]\n processed_data = parallel_load_data(\n file_paths,\n silent_errors=self.silent_errors,\n load_function=process_file,\n max_concurrency=concurrency,\n )\n\n # Use rollup_basefile_data to merge processed data with BaseFile objects\n return self.rollup_data(file_list, processed_data)\n" + }, + "concurrency_multithreading": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Processing Concurrency", + "dynamic": false, + "info": "When multiple files are being processed, the number of files to process concurrently.", + "list": false, + "list_add_label": "Add More", + "name": "concurrency_multithreading", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "delete_server_file_after_processing": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Delete Server File After Processing", + "dynamic": false, + "info": "If true, the Server File Path will be deleted after processing.", + "list": false, + "list_add_label": "Add More", + "name": "delete_server_file_after_processing", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "file_path": { + "_input_type": "HandleInput", + "advanced": true, + "display_name": "Server File Path", + "dynamic": false, + "info": "Data object with a 'file_path' property pointing to server file or a Message object with a path to the file. Supercedes 'Path' but supports same file types.", + "input_types": [ + "Data", + "Message" + ], + "list": true, + "list_add_label": "Add More", + "name": "file_path", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "ignore_unspecified_files": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Ignore Unspecified Files", + "dynamic": false, + "info": "If true, Data with no 'file_path' property will be ignored.", + "list": false, + "list_add_label": "Add More", + "name": "ignore_unspecified_files", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "ignore_unsupported_extensions": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Ignore Unsupported Extensions", + "dynamic": false, + "info": "If true, files with unsupported extensions will not be processed.", + "list": false, + "list_add_label": "Add More", + "name": "ignore_unsupported_extensions", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "path": { + "_input_type": "FileInput", + "advanced": false, + "display_name": "Files", + "dynamic": false, + "fileTypes": [ + "txt", + "md", + "mdx", + "csv", + "json", + "yaml", + "yml", + "xml", + "html", + "htm", + "pdf", + "docx", + "py", + "sh", + "sql", + "js", + "ts", + "tsx", + "zip", + "tar", + "tgz", + "bz2", + "gz" + ], + "file_path": [], + "info": "Supported file extensions: txt, md, mdx, csv, json, yaml, yml, xml, html, htm, pdf, docx, py, sh, sql, js, ts, tsx; optionally bundled in file extensions: zip, tar, tgz, bz2, gz", + "list": true, + "list_add_label": "Add More", + "name": "path", + "placeholder": "", + "required": false, + "show": true, + "temp_file": false, + "title_case": false, + "trace_as_metadata": true, + "type": "file", + "value": "" + }, + "separator": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "Separator", + "dynamic": false, + "info": "Specify the separator to use between multiple outputs in Message format.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "separator", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "\n\n" + }, + "silent_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Silent Errors", + "dynamic": false, + "info": "If true, errors will not raise an exception.", + "list": false, + "list_add_label": "Add More", + "name": "silent_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "use_multithreading": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "[Deprecated] Use Multithreading", + "dynamic": false, + "info": "Set 'Processing Concurrency' greater than 1 to enable multithreading.", + "list": false, + "list_add_label": "Add More", + "name": "use_multithreading", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + } + }, + "tool_mode": false + }, + "showNode": true, + "type": "File" + }, + "dragging": false, + "id": "File-cLJI5", + "measured": { + "height": 233, + "width": 320 + }, + "position": { + "x": 148.2876240515333, + "y": -84.59506014967624 + }, "selected": true, "type": "genericNode" } ], "viewport": { - "x": 201.52975647724884, - "y": 410.819941953365, - "zoom": 0.6386710713834723 + "x": 262.39677390913835, + "y": 326.83109064058834, + "zoom": 0.6244838480835059 } }, "description": "Integrates PDF reading with a language model to answer document-specific questions. Ideal for small-scale texts, it facilitates direct queries with immediate insights.", "endpoint_name": null, - "id": "e088aa15-23da-4839-b3f0-eb733b973a8b", + "id": "8aa6b909-19cb-4e09-8395-a107d6aa278b", "is_component": false, - "last_tested_version": "1.2.0", + "last_tested_version": "1.4.3", "name": "Document Q&A", "tags": [ "rag", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json index 25625409e..038b673d4 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-Mqzss", + "id": "ChatInput-xyuQP", "name": "message", "output_types": [ "Message" @@ -15,19 +15,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "OpenAIModel-gXjiP", + "id": "OpenAIModel-uwgKb", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-Mqzss{œdataTypeœ:œChatInputœ,œidœ:œChatInput-Mqzssœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-gXjiP{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-gXjiPœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-xyuQP{œdataTypeœ:œChatInputœ,œidœ:œChatInput-xyuQPœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-uwgKb{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-uwgKbœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-Mqzss", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-Mqzssœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-gXjiP", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-gXjiPœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-xyuQP", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-xyuQPœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "OpenAIModel-uwgKb", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-uwgKbœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -35,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-mtnlM", + "id": "Prompt-2aw7O", "name": "prompt", "output_types": [ "Message" @@ -43,19 +43,19 @@ }, "targetHandle": { "fieldName": "system_message", - "id": "OpenAIModel-gXjiP", + "id": "OpenAIModel-uwgKb", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-mtnlM{œdataTypeœ:œPromptœ,œidœ:œPrompt-mtnlMœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-gXjiP{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-gXjiPœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Prompt-2aw7O{œdataTypeœ:œPromptœ,œidœ:œPrompt-2aw7Oœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-uwgKb{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-uwgKbœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-mtnlM", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-mtnlMœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-gXjiP", - "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-gXjiPœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-2aw7O", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-2aw7Oœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "OpenAIModel-uwgKb", + "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-uwgKbœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -63,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "OpenAIModel", - "id": "OpenAIModel-gXjiP", + "id": "OpenAIModel-uwgKb", "name": "text_output", "output_types": [ "Message" @@ -71,7 +71,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-Er0pP", + "id": "ChatOutput-cBToy", "inputTypes": [ "Data", "DataFrame", @@ -80,12 +80,12 @@ "type": "str" } }, - "id": "reactflow__edge-OpenAIModel-gXjiP{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-gXjiPœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Er0pP{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Er0pPœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-OpenAIModel-uwgKb{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-uwgKbœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-cBToy{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-cBToyœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "OpenAIModel-gXjiP", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-gXjiPœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-Er0pP", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Er0pPœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "OpenAIModel-uwgKb", + "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-uwgKbœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-cBToy", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-cBToyœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -93,7 +93,7 @@ "data": { "sourceHandle": { "dataType": "TypeConverterComponent", - "id": "TypeConverterComponent-6PlBG", + "id": "TypeConverterComponent-6kqHz", "name": "message_output", "output_types": [ "Message" @@ -101,7 +101,7 @@ }, "targetHandle": { "fieldName": "memory", - "id": "Prompt-mtnlM", + "id": "Prompt-2aw7O", "inputTypes": [ "Message", "Text" @@ -109,18 +109,20 @@ "type": "str" } }, - "id": "reactflow__edge-TypeConverterComponent-6PlBG{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-6PlBGœ,œnameœ:œmessage_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-mtnlM{œfieldNameœ:œmemoryœ,œidœ:œPrompt-mtnlMœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-TypeConverterComponent-6kqHz{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-6kqHzœ,œnameœ:œmessage_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-2aw7O{œfieldNameœ:œmemoryœ,œidœ:œPrompt-2aw7Oœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "TypeConverterComponent-6PlBG", - "sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-6PlBGœ, œnameœ: œmessage_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-mtnlM", - "targetHandle": "{œfieldNameœ: œmemoryœ, œidœ: œPrompt-mtnlMœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "source": "TypeConverterComponent-6kqHz", + "sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-6kqHzœ, œnameœ: œmessage_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-2aw7O", + "targetHandle": "{œfieldNameœ: œmemoryœ, œidœ: œPrompt-2aw7Oœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { + "animated": false, + "className": "", "data": { "sourceHandle": { "dataType": "Memory", - "id": "Memory-OBr5W", + "id": "Memory-Esy2a", "name": "dataframe", "output_types": [ "DataFrame" @@ -128,7 +130,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "TypeConverterComponent-6PlBG", + "id": "TypeConverterComponent-6kqHz", "inputTypes": [ "Message", "Data", @@ -137,17 +139,18 @@ "type": "other" } }, - "id": "xy-edge__Memory-OBr5W{œdataTypeœ:œMemoryœ,œidœ:œMemory-OBr5Wœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-TypeConverterComponent-6PlBG{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-6PlBGœ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}", - "source": "Memory-OBr5W", - "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-OBr5Wœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", - "target": "TypeConverterComponent-6PlBG", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-6PlBGœ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}" + "id": "reactflow__edge-Memory-Esy2a{œdataTypeœ:œMemoryœ,œidœ:œMemory-Esy2aœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-TypeConverterComponent-6kqHz{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-6kqHzœ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}", + "selected": false, + "source": "Memory-Esy2a", + "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-Esy2aœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", + "target": "TypeConverterComponent-6kqHz", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-6kqHzœ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-Mqzss", + "id": "ChatInput-xyuQP", "node": { "base_classes": [ "Message" @@ -173,7 +176,7 @@ "frozen": false, "icon": "MessagesSquare", "legacy": false, - "lf_version": "1.0.19.post2", + "lf_version": "1.4.3", "metadata": {}, "output_types": [], "outputs": [ @@ -432,7 +435,7 @@ }, "dragging": false, "height": 234, - "id": "ChatInput-Mqzss", + "id": "ChatInput-xyuQP", "measured": { "height": 234, "width": 320 @@ -453,7 +456,7 @@ "data": { "description": "Display a chat message in the Playground.", "display_name": "Chat Output", - "id": "ChatOutput-Er0pP", + "id": "ChatOutput-cBToy", "node": { "base_classes": [ "Message" @@ -479,7 +482,7 @@ "frozen": false, "icon": "MessagesSquare", "legacy": false, - "lf_version": "1.0.19.post2", + "lf_version": "1.4.3", "metadata": {}, "output_types": [], "outputs": [ @@ -736,7 +739,7 @@ }, "dragging": true, "height": 234, - "id": "ChatOutput-Er0pP", + "id": "ChatOutput-cBToy", "measured": { "height": 234, "width": 320 @@ -755,7 +758,7 @@ }, { "data": { - "id": "note-bo9zi", + "id": "note-WfHA2", "node": { "description": "# Memory Chatbot\n\nA flexible chatbot implementation featuring advanced conversation memory capabilities. This serves as a foundational tool for building chat experiences with persistent context.\n\n## Core Components\n\n1. **Chat Input**\n - Accepts user messages\n - Configures conversation storage\n - Tracks session identity\n\n2. **Chat Memory**\n - Stores and retrieves up to 100 previous messages\n - Maintains conversation context\n - Tracks separate chat sessions\n - Preserves sender information and message order\n\n3. **Prompt**\n - Creates dynamic prompt templates\n - Integrates memory into conversation flow\n\n4. **OpenAI**\n - Processes user input with context\n - Accesses conversation history\n - Includes options for model configuration and API key setup\n\n5. **Chat Output**\n - Displays formatted responses\n - Maintains conversation flow\n - Syncs with memory storage\n\n## Memory Features\n\n- Stores message history\n- Plans conversation trajectory\n- Differentiates between chat sessions\n- Preserves sender and message metadata\n\n## Quick Start\n\n1. **Initialize** with a clear session ID\n2. **Enter** message in Chat Input\n3. **AI Processes** with context from memory\n4. **Response** appears in Chat Output\n5. Context remains available for follow-ups\n\nThis robust system demonstrates thorough memory integration with minimal complexity. 🧠💬\n", "display_name": "", @@ -766,10 +769,10 @@ }, "dragging": false, "height": 736, - "id": "note-bo9zi", + "id": "note-WfHA2", "measured": { "height": 736, - "width": 325 + "width": 324 }, "position": { "x": 1512.8976594415833, @@ -790,7 +793,7 @@ }, { "data": { - "id": "note-yHt6k", + "id": "note-cHuhR", "node": { "description": "## Get Your OpenAI API Key\n\n**Steps**:\n\n1. **Visit** [OpenAI's API Key Page](https://platform.openai.com/api-keys).\n\n2. **Log In/Sign Up**:\n - Log in or create a new OpenAI account.\n\n3. **Generate API Key**:\n - Click \"Create New Secret Key\" to obtain your key.\n\n4. **Store Your Key Securely**:\n - Note it down as it will only display once.\n\n5. **Enter API Key**:\n - Input your key in the OpenAI API Key field within the component setup.\n\nKeep your key safe and manage it responsibly!", "display_name": "", @@ -803,10 +806,10 @@ }, "dragging": false, "height": 325, - "id": "note-yHt6k", + "id": "note-cHuhR", "measured": { "height": 325, - "width": 326 + "width": 325 }, "position": { "x": 2727.7060397092964, @@ -822,326 +825,7 @@ }, { "data": { - "id": "Memory-gWJrq", - "node": { - "base_classes": [ - "Data", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Stores or retrieves stored chat messages from Langflow tables or an external memory.", - "display_name": "Chat Memory", - "documentation": "", - "edited": false, - "field_order": [ - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template" - ], - "frozen": false, - "icon": "message-square-more", - "legacy": false, - "lf_version": "1.0.19.post2", - "metadata": {}, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Message", - "group_outputs": false, - "method": "retrieve_messages_as_text", - "name": "messages_text", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Dataframe", - "group_outputs": false, - "method": "retrieve_messages_dataframe", - "name": "dataframe", - "selected": "DataFrame", - "tool_mode": true, - "types": [ - "DataFrame" - ], - "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": "from typing import Any, cast\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs.inputs import DropdownInput, HandleInput, IntInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.memory import aget_messages, astore_message\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\nfrom langflow.utils.component_utils import set_current_fields, set_field_display\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Stores or retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n default_keys = [\"mode\", \"memory\"]\n mode_config = {\n \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\"],\n }\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Retrieve\", \"Store\"],\n value=\"Retrieve\",\n info=\"Operation mode: Store messages or Retrieve messages.\",\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The chat message to be stored.\",\n tool_mode=True,\n dynamic=True,\n show=False,\n ),\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"sender_type\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender\",\n display_name=\"Sender\",\n info=\"The sender of the message. Might be Machine or User. \"\n \"If empty, the current sender parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n show=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n show=False,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n value=\"\",\n advanced=True,\n ),\n DropdownInput(\n name=\"order\",\n display_name=\"Order\",\n options=[\"Ascending\", \"Descending\"],\n value=\"Ascending\",\n info=\"Order of the messages.\",\n advanced=True,\n tool_mode=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {sender} or any other key in the message data.\",\n value=\"{sender_name}: {text}\",\n advanced=True,\n show=False,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Message\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True),\n Output(display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True),\n ]\n\n def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:\n \"\"\"Dynamically show only the relevant output based on the selected output type.\"\"\"\n if field_name == \"mode\":\n # Start with empty outputs\n frontend_node[\"outputs\"] = []\n if field_value == \"Store\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Stored Messages\",\n name=\"stored_messages\",\n method=\"store_message\",\n hidden=True,\n dynamic=True,\n )\n ]\n if field_value == \"Retrieve\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Messages\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True\n ),\n Output(\n display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True\n ),\n ]\n return frontend_node\n\n async def store_message(self) -> Message:\n message = Message(text=self.message) if isinstance(self.message, str) else self.message\n\n message.session_id = self.session_id or message.session_id\n message.sender = self.sender or message.sender or MESSAGE_SENDER_AI\n message.sender_name = self.sender_name or message.sender_name or MESSAGE_SENDER_NAME_AI\n\n stored_messages: list[Message] = []\n\n if self.memory:\n self.memory.session_id = message.session_id\n lc_message = message.to_lc_message()\n await self.memory.aadd_messages([lc_message])\n\n stored_messages = await self.memory.aget_messages() or []\n\n stored_messages = [Message.from_lc_message(m) for m in stored_messages] if stored_messages else []\n\n if message.sender:\n stored_messages = [m for m in stored_messages if m.sender == message.sender]\n else:\n await astore_message(message, flow_id=self.graph.flow_id)\n stored_messages = (\n await aget_messages(\n session_id=message.session_id, sender_name=message.sender_name, sender=message.sender\n )\n or []\n )\n\n if not stored_messages:\n msg = \"No messages were stored. Please ensure that the session ID and sender are properly set.\"\n raise ValueError(msg)\n\n stored_message = stored_messages[0]\n self.status = stored_message\n return stored_message\n\n async def retrieve_messages(self) -> Data:\n sender_type = self.sender_type\n sender_name = self.sender_name\n session_id = self.session_id\n n_messages = self.n_messages\n order = \"DESC\" if self.order == \"Descending\" else \"ASC\"\n\n if sender_type == \"Machine and User\":\n sender_type = None\n\n if self.memory and not hasattr(self.memory, \"aget_messages\"):\n memory_name = type(self.memory).__name__\n err_msg = f\"External Memory object ({memory_name}) must have 'aget_messages' method.\"\n raise AttributeError(err_msg)\n # Check if n_messages is None or 0\n if n_messages == 0:\n stored = []\n elif self.memory:\n # override session_id\n self.memory.session_id = session_id\n\n stored = await self.memory.aget_messages()\n # langchain memories are supposed to return messages in ascending order\n if order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender_type:\n expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n stored = await aget_messages(\n sender=sender_type,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n self.status = stored\n return cast(Data, stored)\n\n async def retrieve_messages_as_text(self) -> Message:\n stored_text = data_to_text(self.template, await self.retrieve_messages())\n self.status = stored_text\n return Message(text=stored_text)\n\n async def retrieve_messages_dataframe(self) -> DataFrame:\n \"\"\"Convert the retrieved messages into a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the message data.\n \"\"\"\n messages = await self.retrieve_messages()\n return DataFrame(messages)\n\n def update_build_config(\n self,\n build_config: dotdict,\n field_value: Any, # noqa: ARG002\n field_name: str | None = None, # noqa: ARG002\n ) -> dotdict:\n return set_current_fields(\n build_config=build_config,\n action_fields=self.mode_config,\n selected_action=build_config[\"mode\"][\"value\"],\n default_fields=self.default_keys,\n func=set_field_display,\n )\n" - }, - "memory": { - "_input_type": "HandleInput", - "advanced": true, - "display_name": "External Memory", - "dynamic": false, - "info": "Retrieve messages from an external memory. If empty, it will use the Langflow tables.", - "input_types": [ - "Memory" - ], - "list": false, - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Message", - "dynamic": true, - "info": "The chat message to be stored.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "message", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": false, - "display_name": "Mode", - "dynamic": false, - "info": "Operation mode: Store messages or Retrieve messages.", - "name": "mode", - "options": [ - "Retrieve", - "Store" - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tab", - "value": "Retrieve" - }, - "n_messages": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Number of Messages", - "dynamic": false, - "info": "Number of messages to retrieve.", - "list": false, - "name": "n_messages", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Machine and User" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "sender_type": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender Type", - "dynamic": false, - "info": "Filter by sender type.", - "name": "sender_type", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Machine and User" - }, - "session_id": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "session_id", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "display_name": "Template", - "dynamic": false, - "info": "The template to use for formatting the data. It can contain the keys {text}, {sender} or any other key in the message data.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" - } - }, - "tool_mode": false - }, - "type": "Memory" - }, - "dragging": false, - "height": 264, - "id": "Memory-gWJrq", - "measured": { - "height": 264, - "width": 320 - }, - "position": { - "x": 1947.7805399474369, - "y": 766.1115984799474 - }, - "positionAbsolute": { - "x": 1947.7805399474369, - "y": 766.1115984799474 - }, - "selected": false, - "type": "genericNode", - "width": 320 - }, - { - "data": { - "id": "Prompt-yhdMP", + "id": "Prompt-2aw7O", "node": { "base_classes": [ "Message" @@ -1168,7 +852,7 @@ "is_input": null, "is_output": null, "legacy": false, - "lf_version": "1.0.19.post2", + "lf_version": "1.4.3", "metadata": {}, "name": "", "output_types": [], @@ -1279,14 +963,14 @@ }, "dragging": false, "height": 347, - "id": "Prompt-mtnlM", + "id": "Prompt-2aw7O", "measured": { "height": 347, "width": 320 }, "position": { - "x": 2327.422938009026, - "y": 675.992123914672 + "x": 2351.863651394379, + "y": 636.2759646634735 }, "positionAbsolute": { "x": 2327.422938009026, @@ -1298,7 +982,7 @@ }, { "data": { - "id": "OpenAIModel-gXjiP", + "id": "OpenAIModel-uwgKb", "node": { "base_classes": [ "LanguageModel", @@ -1329,6 +1013,7 @@ "icon": "OpenAI", "key": "OpenAIModel", "legacy": false, + "lf_version": "1.4.3", "metadata": { "keywords": [ "model", @@ -1388,7 +1073,7 @@ "show": true, "title_case": false, "type": "str", - "value": "" + "value": "OPENAI_API_KEY" }, "code": { "advanced": true, @@ -1674,9 +1359,9 @@ "type": "OpenAIModel" }, "dragging": false, - "id": "OpenAIModel-gXjiP", + "id": "OpenAIModel-uwgKb", "measured": { - "height": 537, + "height": 539, "width": 320 }, "position": { @@ -1688,7 +1373,7 @@ }, { "data": { - "id": "TypeConverterComponent-6PlBG", + "id": "TypeConverterComponent-6kqHz", "node": { "base_classes": [ "Message" @@ -1707,6 +1392,7 @@ "frozen": false, "icon": "repeat", "legacy": false, + "lf_version": "1.4.3", "metadata": {}, "minimized": false, "output_types": [], @@ -1799,21 +1485,21 @@ "type": "TypeConverterComponent" }, "dragging": false, - "id": "TypeConverterComponent-6PlBG", + "id": "TypeConverterComponent-6kqHz", "measured": { - "height": 261, + "height": 262, "width": 320 }, "position": { - "x": 2015.8179098384944, - "y": 984.8081816210474 + "x": 1982.2119289336342, + "y": 949.6746561296028 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "Memory-OBr5W", + "id": "Memory-Esy2a", "node": { "base_classes": [ "DataFrame" @@ -1841,6 +1527,7 @@ "icon": "message-square-more", "key": "Memory", "legacy": false, + "lf_version": "1.4.3", "metadata": {}, "minimized": false, "output_types": [], @@ -2131,30 +1818,30 @@ "type": "Memory" }, "dragging": false, - "id": "Memory-OBr5W", + "id": "Memory-Esy2a", "measured": { "height": 217, "width": 320 }, "position": { - "x": 1768.3132819856035, - "y": 639.5677452473304 + "x": 1872.1863138733531, + "y": 662.4809140460989 }, - "selected": true, + "selected": false, "type": "genericNode" } ], "viewport": { - "x": -777.2588770106167, - "y": 42.43614864750725, - "zoom": 0.5481262211197415 + "x": -844.2279175744859, + "y": -37.56256528430163, + "zoom": 0.6546453758419618 } }, "description": "Create a chatbot that saves and references previous messages, enabling the model to maintain context throughout the conversation.", "endpoint_name": null, - "id": "753b0efa-9a02-48ce-b9e8-b09244b1c110", + "id": "c4833c20-c17f-40e2-88d9-34dfed9f1fc2", "is_component": false, - "last_tested_version": "1.4.2", + "last_tested_version": "1.4.3", "name": "Memory Chatbot", "tags": [ "chatbots", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json b/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json index d0e90e18c..053f593ce 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-7dhXG", + "id": "ChatInput-FQZVj", "name": "message", "output_types": [ "Message" @@ -15,19 +15,19 @@ }, "targetHandle": { "fieldName": "search_query", - "id": "ArXivComponent-8YHhw", + "id": "ArXivComponent-hsHDF", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-7dhXG{œdataTypeœ:œChatInputœ,œidœ:œChatInput-7dhXGœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ArXivComponent-8YHhw{œfieldNameœ:œsearch_queryœ,œidœ:œArXivComponent-8YHhwœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-FQZVj{œdataTypeœ:œChatInputœ,œidœ:œChatInput-FQZVjœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ArXivComponent-hsHDF{œfieldNameœ:œsearch_queryœ,œidœ:œArXivComponent-hsHDFœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-7dhXG", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-7dhXGœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "ArXivComponent-8YHhw", - "targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œArXivComponent-8YHhwœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-FQZVj", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-FQZVjœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "ArXivComponent-hsHDF", + "targetHandle": "{œfieldNameœ: œsearch_queryœ, œidœ: œArXivComponent-hsHDFœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -35,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "ArXivComponent", - "id": "ArXivComponent-8YHhw", + "id": "ArXivComponent-hsHDF", "name": "dataframe", "output_types": [ "DataFrame" @@ -43,19 +43,19 @@ }, "targetHandle": { "fieldName": "data", - "id": "LoopComponent-dkM1v", + "id": "LoopComponent-ukukr", "inputTypes": [ "DataFrame" ], "type": "other" } }, - "id": "reactflow__edge-ArXivComponent-8YHhw{œdataTypeœ:œArXivComponentœ,œidœ:œArXivComponent-8YHhwœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-LoopComponent-dkM1v{œfieldNameœ:œdataœ,œidœ:œLoopComponent-dkM1vœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-ArXivComponent-hsHDF{œdataTypeœ:œArXivComponentœ,œidœ:œArXivComponent-hsHDFœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-LoopComponent-ukukr{œfieldNameœ:œdataœ,œidœ:œLoopComponent-ukukrœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}", "selected": false, - "source": "ArXivComponent-8YHhw", - "sourceHandle": "{œdataTypeœ: œArXivComponentœ, œidœ: œArXivComponent-8YHhwœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", - "target": "LoopComponent-dkM1v", - "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œLoopComponent-dkM1vœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}" + "source": "ArXivComponent-hsHDF", + "sourceHandle": "{œdataTypeœ: œArXivComponentœ, œidœ: œArXivComponent-hsHDFœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", + "target": "LoopComponent-ukukr", + "targetHandle": "{œfieldNameœ: œdataœ, œidœ: œLoopComponent-ukukrœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -63,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "LoopComponent", - "id": "LoopComponent-dkM1v", + "id": "LoopComponent-ukukr", "name": "item", "output_types": [ "Data" @@ -71,7 +71,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "ParserComponent-uSCVe", + "id": "ParserComponent-sJ2Cp", "inputTypes": [ "DataFrame", "Data" @@ -79,12 +79,12 @@ "type": "other" } }, - "id": "reactflow__edge-LoopComponent-dkM1v{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-dkM1vœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}-ParserComponent-uSCVe{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-uSCVeœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-LoopComponent-ukukr{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-ukukrœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}-ParserComponent-sJ2Cp{œfieldNameœ:œinput_dataœ,œidœ:œParserComponent-sJ2Cpœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", "selected": false, - "source": "LoopComponent-dkM1v", - "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-dkM1vœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}", - "target": "ParserComponent-uSCVe", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œParserComponent-uSCVeœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" + "source": "LoopComponent-ukukr", + "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-ukukrœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}", + "target": "ParserComponent-sJ2Cp", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œParserComponent-sJ2Cpœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -92,7 +92,7 @@ "data": { "sourceHandle": { "dataType": "LoopComponent", - "id": "LoopComponent-dkM1v", + "id": "LoopComponent-ukukr", "name": "done", "output_types": [ "DataFrame" @@ -100,7 +100,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "TypeConverterComponent-0TFCA", + "id": "TypeConverterComponent-5rZSf", "inputTypes": [ "Message", "Data", @@ -109,12 +109,12 @@ "type": "other" } }, - "id": "reactflow__edge-LoopComponent-dkM1v{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-dkM1vœ,œnameœ:œdoneœ,œoutput_typesœ:[œDataFrameœ]}-TypeConverterComponent-0TFCA{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-0TFCAœ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-LoopComponent-ukukr{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-ukukrœ,œnameœ:œdoneœ,œoutput_typesœ:[œDataFrameœ]}-TypeConverterComponent-5rZSf{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-5rZSfœ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}", "selected": false, - "source": "LoopComponent-dkM1v", - "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-dkM1vœ, œnameœ: œdoneœ, œoutput_typesœ: [œDataFrameœ]}", - "target": "TypeConverterComponent-0TFCA", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-0TFCAœ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}" + "source": "LoopComponent-ukukr", + "sourceHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-ukukrœ, œnameœ: œdoneœ, œoutput_typesœ: [œDataFrameœ]}", + "target": "TypeConverterComponent-5rZSf", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-5rZSfœ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -122,7 +122,7 @@ "data": { "sourceHandle": { "dataType": "TypeConverterComponent", - "id": "TypeConverterComponent-0TFCA", + "id": "TypeConverterComponent-5rZSf", "name": "message_output", "output_types": [ "Message" @@ -130,7 +130,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-O3R2b", + "id": "ChatOutput-ou9sf", "inputTypes": [ "Data", "DataFrame", @@ -139,12 +139,12 @@ "type": "other" } }, - "id": "reactflow__edge-TypeConverterComponent-0TFCA{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-0TFCAœ,œnameœ:œmessage_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-O3R2b{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-O3R2bœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-TypeConverterComponent-5rZSf{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-5rZSfœ,œnameœ:œmessage_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-ou9sf{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-ou9sfœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "TypeConverterComponent-0TFCA", - "sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-0TFCAœ, œnameœ: œmessage_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-O3R2b", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-O3R2bœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "TypeConverterComponent-5rZSf", + "sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-5rZSfœ, œnameœ: œmessage_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-ou9sf", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-ou9sfœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -152,7 +152,7 @@ "data": { "sourceHandle": { "dataType": "ParserComponent", - "id": "ParserComponent-uSCVe", + "id": "ParserComponent-sJ2Cp", "name": "parsed_text", "output_types": [ "Message" @@ -160,19 +160,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "LanguageModelComponent-huxaM", + "id": "LanguageModelComponent-2FSUA", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ParserComponent-uSCVe{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-uSCVeœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-huxaM{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-huxaMœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ParserComponent-sJ2Cp{œdataTypeœ:œParserComponentœ,œidœ:œParserComponent-sJ2Cpœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-2FSUA{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-2FSUAœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ParserComponent-uSCVe", - "sourceHandle": "{œdataTypeœ: œParserComponentœ, œidœ: œParserComponent-uSCVeœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", - "target": "LanguageModelComponent-huxaM", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-huxaMœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ParserComponent-sJ2Cp", + "sourceHandle": "{œdataTypeœ: œParserComponentœ, œidœ: œParserComponent-sJ2Cpœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-2FSUA", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-2FSUAœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -180,61 +180,60 @@ "data": { "sourceHandle": { "dataType": "LanguageModelComponent", - "id": "LanguageModelComponent-huxaM", + "id": "LanguageModelComponent-2FSUA", "name": "text_output", "output_types": [ "Message" ] }, "targetHandle": { - "fieldName": "message", - "id": "MessagetoData-uaDsB", + "fieldName": "input_data", + "id": "TypeConverterComponent-WY9tm", "inputTypes": [ - "Message" + "Message", + "Data", + "DataFrame" ], - "type": "str" + "type": "other" } }, - "id": "reactflow__edge-LanguageModelComponent-huxaM{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-huxaMœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-MessagetoData-uaDsB{œfieldNameœ:œmessageœ,œidœ:œMessagetoData-uaDsBœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-LanguageModelComponent-2FSUA{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-2FSUAœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-TypeConverterComponent-WY9tm{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-WY9tmœ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}", "selected": false, - "source": "LanguageModelComponent-huxaM", - "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-huxaMœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "MessagetoData-uaDsB", - "targetHandle": "{œfieldNameœ: œmessageœ, œidœ: œMessagetoData-uaDsBœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "LanguageModelComponent-2FSUA", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-2FSUAœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "TypeConverterComponent-WY9tm", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-WY9tmœ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}" }, { - "animated": false, - "className": "", "data": { "sourceHandle": { - "dataType": "MessagetoData", - "id": "MessagetoData-uaDsB", - "name": "data", + "dataType": "TypeConverterComponent", + "id": "TypeConverterComponent-WY9tm", + "name": "data_output", "output_types": [ "Data" ] }, "targetHandle": { "dataType": "LoopComponent", - "id": "LoopComponent-dkM1v", + "id": "LoopComponent-ukukr", "name": "item", "output_types": [ "Data" ] } }, - "id": "reactflow__edge-MessagetoData-uaDsB{œdataTypeœ:œMessagetoDataœ,œidœ:œMessagetoData-uaDsBœ,œnameœ:œdataœ,œoutput_typesœ:[œDataœ]}-LoopComponent-dkM1v{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-dkM1vœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}", - "selected": false, - "source": "MessagetoData-uaDsB", - "sourceHandle": "{œdataTypeœ: œMessagetoDataœ, œidœ: œMessagetoData-uaDsBœ, œnameœ: œdataœ, œoutput_typesœ: [œDataœ]}", - "target": "LoopComponent-dkM1v", - "targetHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-dkM1vœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}" + "id": "xy-edge__TypeConverterComponent-WY9tm{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-WY9tmœ,œnameœ:œdata_outputœ,œoutput_typesœ:[œDataœ]}-LoopComponent-ukukr{œdataTypeœ:œLoopComponentœ,œidœ:œLoopComponent-ukukrœ,œnameœ:œitemœ,œoutput_typesœ:[œDataœ]}", + "source": "TypeConverterComponent-WY9tm", + "sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-WY9tmœ, œnameœ: œdata_outputœ, œoutput_typesœ: [œDataœ]}", + "target": "LoopComponent-ukukr", + "targetHandle": "{œdataTypeœ: œLoopComponentœ, œidœ: œLoopComponent-ukukrœ, œnameœ: œitemœ, œoutput_typesœ: [œDataœ]}" } ], "nodes": [ { "data": { - "id": "ArXivComponent-8YHhw", + "id": "ArXivComponent-hsHDF", "node": { "base_classes": [ "DataFrame" @@ -371,9 +370,9 @@ "type": "ArXivComponent" }, "dragging": false, - "id": "ArXivComponent-8YHhw", + "id": "ArXivComponent-hsHDF", "measured": { - "height": 368, + "height": 367, "width": 320 }, "position": { @@ -385,7 +384,7 @@ }, { "data": { - "id": "ChatOutput-O3R2b", + "id": "ChatOutput-ou9sf", "node": { "base_classes": [ "Message" @@ -680,7 +679,7 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-O3R2b", + "id": "ChatOutput-ou9sf", "measured": { "height": 48, "width": 192 @@ -694,7 +693,7 @@ }, { "data": { - "id": "ChatInput-7dhXG", + "id": "ChatInput-FQZVj", "node": { "base_classes": [ "Message" @@ -992,7 +991,7 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-7dhXG", + "id": "ChatInput-FQZVj", "measured": { "height": 203, "width": 320 @@ -1006,7 +1005,7 @@ }, { "data": { - "id": "note-A2mJA", + "id": "note-FkBwM", "node": { "description": "# **Langflow Loop Component Template - ArXiv search result Translator** \nThis template translates research paper summaries on ArXiv into Portuguese and summarizes them. \n Using **Langflow’s looping mechanism**, the template iterates through multiple research papers, translates them with the **OpenAI** model component, and outputs an aggregated version of all translated papers. \n\n## Quickstart \n 1. Add your OpenAI API key to the **Language Model** component. \n2. In the **Playground**, enter a query related to a research topic (for example, “Quantum Computing Advancements”). \n\n The flow fetches a list of research papers from ArXiv matching the query. Each paper in the retrieved list is processed one-by-one using the Langflow **Loop component**. \n\n The abstract of each paper is translated into Portuguese by the **OpenAI** model component. \n\n Once all papers are translated, the system aggregates them into a **single structured output**.", "display_name": "", @@ -1017,7 +1016,7 @@ }, "dragging": false, "height": 647, - "id": "note-A2mJA", + "id": "note-FkBwM", "measured": { "height": 647, "width": 576 @@ -1033,7 +1032,7 @@ }, { "data": { - "id": "ParserComponent-uSCVe", + "id": "ParserComponent-sJ2Cp", "node": { "base_classes": [ "Message" @@ -1192,9 +1191,9 @@ "type": "ParserComponent" }, "dragging": false, - "id": "ParserComponent-uSCVe", + "id": "ParserComponent-sJ2Cp", "measured": { - "height": 328, + "height": 327, "width": 320 }, "position": { @@ -1206,7 +1205,7 @@ }, { "data": { - "id": "LoopComponent-dkM1v", + "id": "LoopComponent-ukukr", "node": { "base_classes": [ "Data", @@ -1307,7 +1306,7 @@ "type": "LoopComponent" }, "dragging": false, - "id": "LoopComponent-dkM1v", + "id": "LoopComponent-ukukr", "measured": { "height": 241, "width": 320 @@ -1321,7 +1320,7 @@ }, { "data": { - "id": "TypeConverterComponent-0TFCA", + "id": "TypeConverterComponent-5rZSf", "node": { "base_classes": [ "Message" @@ -1435,9 +1434,9 @@ "type": "TypeConverterComponent" }, "dragging": false, - "id": "TypeConverterComponent-0TFCA", + "id": "TypeConverterComponent-5rZSf", "measured": { - "height": 262, + "height": 261, "width": 320 }, "position": { @@ -1449,7 +1448,7 @@ }, { "data": { - "id": "LanguageModelComponent-huxaM", + "id": "LanguageModelComponent-2FSUA", "node": { "base_classes": [ "LanguageModel", @@ -1492,6 +1491,8 @@ "group_outputs": false, "method": "text_response", "name": "text_output", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1506,6 +1507,8 @@ "group_outputs": false, "method": "build_model", "name": "model_output", + "options": null, + "required_inputs": null, "selected": "LanguageModel", "tool_mode": true, "types": [ @@ -1534,7 +1537,7 @@ "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1587,13 +1590,16 @@ "info": "Select the model to use", "name": "model_name", "options": [ - "claude-opus-4-20250514", - "claude-sonnet-4-20250514", - "claude-3-7-sonnet-latest", - "claude-3-5-sonnet-latest", - "claude-3-5-haiku-latest", - "claude-3-opus-latest", - "claude-3-sonnet-20240229" + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" ], "options_metadata": [], "placeholder": "", @@ -1720,9 +1726,9 @@ "type": "LanguageModelComponent" }, "dragging": false, - "id": "LanguageModelComponent-huxaM", + "id": "LanguageModelComponent-2FSUA", "measured": { - "height": 532, + "height": 531, "width": 320 }, "position": { @@ -1734,26 +1740,29 @@ }, { "data": { - "id": "MessagetoData-uaDsB", + "id": "TypeConverterComponent-WY9tm", "node": { "base_classes": [ - "Data" + "Message", + "Data", + "DataFrame" ], - "beta": true, + "beta": false, "category": "processing", "conditional_paths": [], "custom_fields": {}, - "description": "Convert a Message object to a Data object", - "display_name": "Message to Data", + "description": "Convert between different types (Message, Data, DataFrame)", + "display_name": "Type Convert", "documentation": "", "edited": false, "field_order": [ - "message" + "input_data", + "output_type" ], "frozen": false, - "icon": "message-square-share", - "key": "MessagetoData", - "legacy": true, + "icon": "repeat", + "key": "TypeConverterComponent", + "legacy": false, "metadata": {}, "minimized": false, "output_types": [], @@ -1761,20 +1770,24 @@ { "allows_loop": false, "cache": true, - "display_name": "Data", + "display_name": "Data Output", "group_outputs": false, - "method": "convert_message_to_data", - "name": "data", + "method": "convert_to_data", + "name": "data_output", + "options": null, + "required_inputs": null, "selected": "Data", "tool_mode": true, "types": [ - "Data" + "Message", + "Data", + "DataFrame" ], "value": "__UNDEFINED__" } ], "pinned": false, - "score": 0.008222426499470714, + "score": 0.007568328950209746, "template": { "_type": "Component", "code": { @@ -1793,60 +1806,81 @@ "show": true, "title_case": false, "type": "code", - "value": "from loguru import logger\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.io import MessageInput, Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.message import Message\n\n\nclass MessageToDataComponent(Component):\n display_name = \"Message to Data\"\n description = \"Convert a Message object to a Data object\"\n icon = \"message-square-share\"\n beta = True\n name = \"MessagetoData\"\n legacy = True\n\n inputs = [\n MessageInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The Message object to convert to a Data object\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"convert_message_to_data\"),\n ]\n\n def convert_message_to_data(self) -> Data:\n if isinstance(self.message, Message):\n # Convert Message to Data\n return Data(data=self.message.data)\n\n msg = \"Error converting Message to Data: Input must be a Message object\"\n logger.opt(exception=True).debug(msg)\n self.status = msg\n return Data(data={\"error\": msg})\n" + "value": "from typing import Any\n\nfrom langflow.custom import Component\nfrom langflow.io import HandleInput, Output, TabInput\nfrom langflow.schema import Data, DataFrame, Message\n\n\ndef convert_to_message(v) -> Message:\n \"\"\"Convert input to Message type.\n\n Args:\n v: Input to convert (Message, Data, DataFrame, or dict)\n\n Returns:\n Message: Converted Message object\n \"\"\"\n return v if isinstance(v, Message) else v.to_message()\n\n\ndef convert_to_data(v: DataFrame | Data | Message | dict) -> Data:\n \"\"\"Convert input to Data type.\n\n Args:\n v: Input to convert (Message, Data, DataFrame, or dict)\n\n Returns:\n Data: Converted Data object\n \"\"\"\n if isinstance(v, dict):\n return Data(v)\n return v if isinstance(v, Data) else v.to_data()\n\n\ndef convert_to_dataframe(v: DataFrame | Data | Message | dict) -> DataFrame:\n \"\"\"Convert input to DataFrame type.\n\n Args:\n v: Input to convert (Message, Data, DataFrame, or dict)\n\n Returns:\n DataFrame: Converted DataFrame object\n \"\"\"\n if isinstance(v, dict):\n return DataFrame([v])\n return v if isinstance(v, DataFrame) else v.to_dataframe()\n\n\nclass TypeConverterComponent(Component):\n display_name = \"Type Convert\"\n description = \"Convert between different types (Message, Data, DataFrame)\"\n icon = \"repeat\"\n\n inputs = [\n HandleInput(\n name=\"input_data\",\n display_name=\"Input\",\n input_types=[\"Message\", \"Data\", \"DataFrame\"],\n info=\"Accept Message, Data or DataFrame as input\",\n required=True,\n ),\n TabInput(\n name=\"output_type\",\n display_name=\"Output Type\",\n options=[\"Message\", \"Data\", \"DataFrame\"],\n info=\"Select the desired output data type\",\n real_time_refresh=True,\n value=\"Message\",\n ),\n ]\n\n outputs = [\n Output(\n display_name=\"Message Output\",\n name=\"message_output\",\n method=\"convert_to_message\",\n )\n ]\n\n def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:\n \"\"\"Dynamically show only the relevant output based on the selected output type.\"\"\"\n if field_name == \"output_type\":\n # Start with empty outputs\n frontend_node[\"outputs\"] = []\n\n # Add only the selected output type\n if field_value == \"Message\":\n frontend_node[\"outputs\"].append(\n Output(\n display_name=\"Message Output\",\n name=\"message_output\",\n method=\"convert_to_message\",\n ).to_dict()\n )\n elif field_value == \"Data\":\n frontend_node[\"outputs\"].append(\n Output(\n display_name=\"Data Output\",\n name=\"data_output\",\n method=\"convert_to_data\",\n ).to_dict()\n )\n elif field_value == \"DataFrame\":\n frontend_node[\"outputs\"].append(\n Output(\n display_name=\"DataFrame Output\",\n name=\"dataframe_output\",\n method=\"convert_to_dataframe\",\n ).to_dict()\n )\n\n return frontend_node\n\n def convert_to_message(self) -> Message:\n \"\"\"Convert input to Message type.\"\"\"\n input_value = self.input_data[0] if isinstance(self.input_data, list) else self.input_data\n\n # Handle string input by converting to Message first\n if isinstance(input_value, str):\n input_value = Message(text=input_value)\n\n result = convert_to_message(input_value)\n self.status = result\n return result\n\n def convert_to_data(self) -> Data:\n \"\"\"Convert input to Data type.\"\"\"\n input_value = self.input_data[0] if isinstance(self.input_data, list) else self.input_data\n\n # Handle string input by converting to Message first\n if isinstance(input_value, str):\n input_value = Message(text=input_value)\n\n result = convert_to_data(input_value)\n self.status = result\n return result\n\n def convert_to_dataframe(self) -> DataFrame:\n \"\"\"Convert input to DataFrame type.\"\"\"\n input_value = self.input_data[0] if isinstance(self.input_data, list) else self.input_data\n\n # Handle string input by converting to Message first\n if isinstance(input_value, str):\n input_value = Message(text=input_value)\n\n result = convert_to_dataframe(input_value)\n self.status = result\n return result\n" }, - "message": { - "_input_type": "MessageInput", + "input_data": { + "_input_type": "HandleInput", "advanced": false, - "display_name": "Message", + "display_name": "Input", "dynamic": false, - "info": "The Message object to convert to a Data object", + "info": "Accept Message, Data or DataFrame as input", "input_types": [ - "Message" + "Message", + "Data", + "DataFrame" ], "list": false, "list_add_label": "Add More", - "load_from_db": false, - "name": "message", + "name": "input_data", "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "output_type": { + "_input_type": "TabInput", + "advanced": false, + "display_name": "Output Type", + "dynamic": false, + "info": "Select the desired output data type", + "name": "output_type", + "options": [ + "Message", + "Data", + "DataFrame" + ], + "placeholder": "", + "real_time_refresh": true, "required": false, "show": true, "title_case": false, "tool_mode": false, - "trace_as_input": true, "trace_as_metadata": true, - "type": "str", - "value": "" + "type": "tab", + "value": "Data" } }, "tool_mode": false }, "showNode": true, - "type": "MessagetoData" + "type": "TypeConverterComponent" }, "dragging": false, - "id": "MessagetoData-uaDsB", + "id": "TypeConverterComponent-WY9tm", "measured": { - "height": 203, + "height": 261, "width": 320 }, "position": { - "x": 1836.3049922790483, - "y": 411.76970008520357 + "x": 1842.690896003052, + "y": 374.08100578248695 }, - "selected": false, + "selected": true, "type": "genericNode" } ], "viewport": { - "x": 269.23666655845534, - "y": 307.2875075099402, - "zoom": 0.46271902027504264 + "x": -214.9740744044314, + "y": 116.1497506096415, + "zoom": 0.5583331791544022 } }, "description": "This template iterates over search results using LoopComponent and translates each result into Portuguese automatically. 🚀", "endpoint_name": null, - "id": "07f1c000-7ebe-4655-8421-06e012fb6da6", + "id": "dbb63177-cc76-420a-a74e-8dc336a70d65", "is_component": false, "last_tested_version": "1.4.3", "name": "Research Translation Loop", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json index c0a984bbe..9226d1428 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json @@ -3,39 +3,11 @@ "edges": [ { "animated": false, - "data": { - "sourceHandle": { - "dataType": "Agent", - "id": "Agent-qYZ9W", - "name": "response", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-aHj8n", - "inputTypes": [ - "Data", - "DataFrame", - "Message" - ], - "type": "other" - } - }, - "id": "xy-edge__Agent-qYZ9W{œdataTypeœ:œAgentœ,œidœ:œAgent-qYZ9Wœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-aHj8n{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-aHj8nœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", - "selected": false, - "source": "Agent-qYZ9W", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-qYZ9Wœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-aHj8n", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-aHj8nœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" - }, - { - "animated": false, + "className": "", "data": { "sourceHandle": { "dataType": "CalculatorComponent", - "id": "CalculatorComponent-15FSE", + "id": "CalculatorComponent-Sp3Ca", "name": "component_as_tool", "output_types": [ "Tool" @@ -43,52 +15,27 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-qYZ9W", + "id": "Agent-xD3uW", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__CalculatorComponent-15FSE{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-15FSEœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-qYZ9W{œfieldNameœ:œtoolsœ,œidœ:œAgent-qYZ9Wœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "xy-edge__CalculatorComponent-Sp3Ca{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-Sp3Caœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-xD3uW{œfieldNameœ:œtoolsœ,œidœ:œAgent-xD3uWœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "CalculatorComponent-15FSE", - "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-15FSEœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-qYZ9W", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-qYZ9Wœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "CalculatorComponent-Sp3Ca", + "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-Sp3Caœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-xD3uW", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-xD3uWœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, - "data": { - "sourceHandle": { - "dataType": "URL", - "id": "URL-o7GEq", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-qYZ9W", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "xy-edge__URL-o7GEq{œdataTypeœ:œURLœ,œidœ:œURL-o7GEqœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-qYZ9W{œfieldNameœ:œtoolsœ,œidœ:œAgent-qYZ9Wœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "URL-o7GEq", - "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-o7GEqœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-qYZ9W", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-qYZ9Wœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { + "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-2YUmA", + "id": "ChatInput-S6AhV", "name": "message", "output_types": [ "Message" @@ -96,454 +43,83 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-qYZ9W", + "id": "Agent-xD3uW", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "xy-edge__ChatInput-2YUmA{œdataTypeœ:œChatInputœ,œidœ:œChatInput-2YUmAœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-qYZ9W{œfieldNameœ:œinput_valueœ,œidœ:œAgent-qYZ9Wœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "ChatInput-2YUmA", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-2YUmAœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-qYZ9W", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-qYZ9Wœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "id": "xy-edge__ChatInput-S6AhV{œdataTypeœ:œChatInputœ,œidœ:œChatInput-S6AhVœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-xD3uW{œfieldNameœ:œinput_valueœ,œidœ:œAgent-xD3uWœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-S6AhV", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-S6AhVœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-xD3uW", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-xD3uWœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "Agent", + "id": "Agent-xD3uW", + "name": "response", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-WciiI", + "inputTypes": [ + "Data", + "DataFrame", + "Message" + ], + "type": "other" + } + }, + "id": "xy-edge__Agent-xD3uW{œdataTypeœ:œAgentœ,œidœ:œAgent-xD3uWœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-WciiI{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-WciiIœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "selected": false, + "source": "Agent-xD3uW", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-xD3uWœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-WciiI", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-WciiIœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "URLComponent", + "id": "URLComponent-6fRXe", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-xD3uW", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__URLComponent-6fRXe{œdataTypeœ:œURLComponentœ,œidœ:œURLComponent-6fRXeœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-xD3uW{œfieldNameœ:œtoolsœ,œidœ:œAgent-xD3uWœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "selected": false, + "source": "URLComponent-6fRXe", + "sourceHandle": "{œdataTypeœ: œURLComponentœ, œidœ: œURLComponent-6fRXeœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-xD3uW", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-xD3uWœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "description": "Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "URL", - "id": "URL-o7GEq", - "node": { - "base_classes": [ - "Data", - "DataFrame", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Fetch content from one or more web pages, following links recursively.", - "display_name": "URL", - "documentation": "", - "edited": false, - "field_order": [ - "urls", - "format", - "separator", - "clean_extra_whitespace" - ], - "frozen": false, - "icon": "layout-template", - "legacy": false, - "lf_version": "1.2.0", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "hidden": false, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "autoset_encoding": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Autoset Encoding", - "dynamic": false, - "info": "If enabled, automatically sets the encoding of the request.", - "list": false, - "list_add_label": "Add More", - "name": "autoset_encoding", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "check_response_status": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Check Response Status", - "dynamic": false, - "info": "If enabled, checks the response status of the request.", - "list": false, - "list_add_label": "Add More", - "name": "check_response_status", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "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\nimport requests\nfrom bs4 import BeautifulSoup\nfrom langchain_community.document_loaders import RecursiveUrlLoader\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.helpers.data import safe_convert\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SliderInput, TableInput\nfrom langflow.schema import DataFrame, Message\nfrom langflow.services.deps import get_settings_service\n\n# Constants\nDEFAULT_TIMEOUT = 30\nDEFAULT_MAX_DEPTH = 1\nDEFAULT_FORMAT = \"Text\"\nURL_REGEX = re.compile(\n r\"^(https?:\\/\\/)?\" r\"(www\\.)?\" r\"([a-zA-Z0-9.-]+)\" r\"(\\.[a-zA-Z]{2,})?\" r\"(:\\d+)?\" r\"(\\/[^\\s]*)?$\",\n re.IGNORECASE,\n)\n\n\nclass URLComponent(Component):\n \"\"\"A component that loads and parses content from web pages recursively.\n\n This component allows fetching content from one or more URLs, with options to:\n - Control crawl depth\n - Prevent crawling outside the root domain\n - Use async loading for better performance\n - Extract either raw HTML or clean text\n - Configure request headers and timeouts\n \"\"\"\n\n display_name = \"URL\"\n description = \"Fetch content from one or more web pages, following links recursively.\"\n icon = \"layout-template\"\n name = \"URLComponent\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs to crawl recursively, by clicking the '+' button.\",\n is_list=True,\n tool_mode=True,\n placeholder=\"Enter a URL...\",\n list_add_label=\"Add URL\",\n input_types=[],\n ),\n SliderInput(\n name=\"max_depth\",\n display_name=\"Depth\",\n info=(\n \"Controls how many 'clicks' away from the initial page the crawler will go:\\n\"\n \"- depth 1: only the initial page\\n\"\n \"- depth 2: initial page + all pages linked directly from it\\n\"\n \"- depth 3: initial page + direct links + links found on those direct link pages\\n\"\n \"Note: This is about link traversal, not URL path depth.\"\n ),\n value=DEFAULT_MAX_DEPTH,\n range_spec=RangeSpec(min=1, max=5, step=1),\n required=False,\n min_label=\" \",\n max_label=\" \",\n min_label_icon=\"None\",\n max_label_icon=\"None\",\n # slider_input=True\n ),\n BoolInput(\n name=\"prevent_outside\",\n display_name=\"Prevent Outside\",\n info=(\n \"If enabled, only crawls URLs within the same domain as the root URL. \"\n \"This helps prevent the crawler from going to external websites.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"use_async\",\n display_name=\"Use Async\",\n info=(\n \"If enabled, uses asynchronous loading which can be significantly faster \"\n \"but might use more system resources.\"\n ),\n value=True,\n required=False,\n advanced=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 'HTML' for the raw HTML content.\",\n options=[\"Text\", \"HTML\"],\n value=DEFAULT_FORMAT,\n advanced=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout for the request in seconds.\",\n value=DEFAULT_TIMEOUT,\n required=False,\n advanced=True,\n ),\n TableInput(\n name=\"headers\",\n display_name=\"Headers\",\n info=\"The headers to send with the request\",\n table_schema=[\n {\n \"name\": \"key\",\n \"display_name\": \"Header\",\n \"type\": \"str\",\n \"description\": \"Header name\",\n },\n {\n \"name\": \"value\",\n \"display_name\": \"Value\",\n \"type\": \"str\",\n \"description\": \"Header value\",\n },\n ],\n value=[{\"key\": \"User-Agent\", \"value\": get_settings_service().settings.user_agent}],\n advanced=True,\n input_types=[\"DataFrame\"],\n ),\n BoolInput(\n name=\"filter_text_html\",\n display_name=\"Filter Text/HTML\",\n info=\"If enabled, filters out text/css content type from the results.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"continue_on_failure\",\n display_name=\"Continue on Failure\",\n info=\"If enabled, continues crawling even if some requests fail.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"check_response_status\",\n display_name=\"Check Response Status\",\n info=\"If enabled, checks the response status of the request.\",\n value=False,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"autoset_encoding\",\n display_name=\"Autoset Encoding\",\n info=\"If enabled, automatically sets the encoding of the request.\",\n value=True,\n required=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Result\", name=\"page_results\", method=\"fetch_content\"),\n Output(display_name=\"Raw Result\", name=\"raw_results\", method=\"as_message\"),\n ]\n\n @staticmethod\n def validate_url(url: str) -> bool:\n \"\"\"Validates if the given string matches URL pattern.\n\n Args:\n url: The URL string to validate\n\n Returns:\n bool: True if the URL is valid, False otherwise\n \"\"\"\n return bool(URL_REGEX.match(url))\n\n def ensure_url(self, url: str) -> str:\n \"\"\"Ensures the given string is a valid URL.\n\n Args:\n url: The URL string to validate and normalize\n\n Returns:\n str: The normalized URL\n\n Raises:\n ValueError: If the URL is invalid\n \"\"\"\n url = url.strip()\n if not url.startswith((\"http://\", \"https://\")):\n url = \"https://\" + url\n\n if not self.validate_url(url):\n msg = f\"Invalid URL: {url}\"\n raise ValueError(msg)\n\n return url\n\n def _create_loader(self, url: str) -> RecursiveUrlLoader:\n \"\"\"Creates a RecursiveUrlLoader instance with the configured settings.\n\n Args:\n url: The URL to load\n\n Returns:\n RecursiveUrlLoader: Configured loader instance\n \"\"\"\n headers_dict = {header[\"key\"]: header[\"value\"] for header in self.headers}\n extractor = (lambda x: x) if self.format == \"HTML\" else (lambda x: BeautifulSoup(x, \"lxml\").get_text())\n\n return RecursiveUrlLoader(\n url=url,\n max_depth=self.max_depth,\n prevent_outside=self.prevent_outside,\n use_async=self.use_async,\n extractor=extractor,\n timeout=self.timeout,\n headers=headers_dict,\n check_response_status=self.check_response_status,\n continue_on_failure=self.continue_on_failure,\n base_url=url, # Add base_url to ensure consistent domain crawling\n autoset_encoding=self.autoset_encoding, # Enable automatic encoding detection\n exclude_dirs=[], # Allow customization of excluded directories\n link_regex=None, # Allow customization of link filtering\n )\n\n def fetch_url_contents(self) -> list[dict]:\n \"\"\"Load documents from the configured URLs.\n\n Returns:\n List[Data]: List of Data objects containing the fetched content\n\n Raises:\n ValueError: If no valid URLs are provided or if there's an error loading documents\n \"\"\"\n try:\n urls = list({self.ensure_url(url) for url in self.urls if url.strip()})\n logger.info(f\"URLs: {urls}\")\n if not urls:\n msg = \"No valid URLs provided.\"\n raise ValueError(msg)\n\n all_docs = []\n for url in urls:\n logger.info(f\"Loading documents from {url}\")\n\n try:\n loader = self._create_loader(url)\n docs = loader.load()\n\n if not docs:\n logger.warning(f\"No documents found for {url}\")\n continue\n\n logger.info(f\"Found {len(docs)} documents from {url}\")\n all_docs.extend(docs)\n\n except requests.exceptions.RequestException as e:\n logger.exception(f\"Error loading documents from {url}: {e}\")\n continue\n\n if not all_docs:\n msg = \"No documents were successfully loaded from any URL\"\n raise ValueError(msg)\n\n # data = [Data(text=doc.page_content, **doc.metadata) for doc in all_docs]\n data = [\n {\n \"text\": safe_convert(doc.page_content, clean_data=True),\n \"url\": doc.metadata.get(\"source\", \"\"),\n \"title\": doc.metadata.get(\"title\", \"\"),\n \"description\": doc.metadata.get(\"description\", \"\"),\n \"content_type\": doc.metadata.get(\"content_type\", \"\"),\n \"language\": doc.metadata.get(\"language\", \"\"),\n }\n for doc in all_docs\n ]\n except Exception as e:\n error_msg = e.message if hasattr(e, \"message\") else e\n msg = f\"Error loading documents: {error_msg!s}\"\n logger.exception(msg)\n raise ValueError(msg) from e\n return data\n\n def fetch_content(self) -> DataFrame:\n \"\"\"Convert the documents to a DataFrame.\"\"\"\n return DataFrame(data=self.fetch_url_contents())\n\n def as_message(self) -> Message:\n \"\"\"Convert the documents to a Message.\"\"\"\n url_contents = self.fetch_url_contents()\n return Message(text=\"\\n\\n\".join([x[\"text\"] for x in url_contents]), data={\"data\": url_contents})\n" - }, - "continue_on_failure": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Continue on Failure", - "dynamic": false, - "info": "If enabled, continues crawling even if some requests fail.", - "list": false, - "list_add_label": "Add More", - "name": "continue_on_failure", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "filter_text_html": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Filter Text/HTML", - "dynamic": false, - "info": "If enabled, filters out text/css content type from the results.", - "list": false, - "list_add_label": "Add More", - "name": "filter_text_html", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "format": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Output Format", - "dynamic": false, - "info": "Output Format. Use 'Text' to extract the text from the HTML or 'HTML' for the raw HTML content.", - "name": "format", - "options": [ - "Text", - "HTML" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Text" - }, - "headers": { - "_input_type": "TableInput", - "advanced": true, - "display_name": "Headers", - "dynamic": false, - "info": "The headers to send with the request", - "input_types": [ - "DataFrame" - ], - "is_list": true, - "list_add_label": "Add More", - "name": "headers", - "placeholder": "", - "required": false, - "show": true, - "table_icon": "Table", - "table_schema": { - "columns": [ - { - "default": "None", - "description": "Header name", - "disable_edit": false, - "display_name": "Header", - "edit_mode": "popover", - "filterable": true, - "formatter": "text", - "hidden": false, - "name": "key", - "sortable": true, - "type": "str" - }, - { - "default": "None", - "description": "Header value", - "disable_edit": false, - "display_name": "Value", - "edit_mode": "popover", - "filterable": true, - "formatter": "text", - "hidden": false, - "name": "value", - "sortable": true, - "type": "str" - } - ] - }, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "trigger_icon": "Table", - "trigger_text": "Open table", - "type": "table", - "value": [ - { - "key": "User-Agent", - "value": "langflow" - } - ] - }, - "max_depth": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Depth", - "dynamic": false, - "info": "Controls how many 'clicks' away from the initial page the crawler will go:\n- depth 1: only the initial page\n- depth 2: initial page + all pages linked directly from it\n- depth 3: initial page + direct links + links found on those direct link pages\nNote: This is about link traversal, not URL path depth.", - "max_label": " ", - "max_label_icon": "None", - "min_label": " ", - "min_label_icon": "None", - "name": "max_depth", - "placeholder": "", - "range_spec": { - "max": 5.0, - "min": 1.0, - "step": 1.0, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 1 - }, - "prevent_outside": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Prevent Outside", - "dynamic": false, - "info": "If enabled, only crawls URLs within the same domain as the root URL. This helps prevent the crawler from going to external websites.", - "list": false, - "list_add_label": "Add More", - "name": "prevent_outside", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "Timeout for the request in seconds.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 30 - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": { - "urls": { - "default": "", - "description": "", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "URL. fetch_content() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_description": "URL. fetch_content() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "fetch_content", - "name": "fetch_content", - "status": true, - "tags": [ - "fetch_content" - ] - }, - { - "args": { - "urls": { - "default": "", - "description": "", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "URL. fetch_content_text() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_description": "URL. fetch_content_text() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "fetch_content_text", - "name": "fetch_content_text", - "status": true, - "tags": [ - "fetch_content_text" - ] - }, - { - "args": { - "urls": { - "default": "", - "description": "", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "URL. as_dataframe() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_description": "URL. as_dataframe() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "as_dataframe", - "name": "as_dataframe", - "status": true, - "tags": [ - "as_dataframe" - ] - } - ] - }, - "urls": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "URLs", - "dynamic": false, - "info": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", - "input_types": [], - "list": true, - "list_add_label": "Add URL", - "load_from_db": false, - "name": "urls", - "placeholder": "Enter a URL...", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "use_async": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Use Async", - "dynamic": false, - "info": "If enabled, uses asynchronous loading which can be significantly faster but might use more system resources.", - "list": false, - "list_add_label": "Add More", - "name": "use_async", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": true - }, - "selected_output": "component_as_tool", - "type": "URL" - }, - "dragging": false, - "id": "URL-o7GEq", - "measured": { - "height": 523, - "width": 320 - }, - "position": { - "x": 1236.8269016193576, - "y": -173.8644169438124 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "note-wtgw9", + "id": "note-ukwn1", "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": "", @@ -555,10 +131,10 @@ "type": "note" }, "dragging": false, - "id": "note-wtgw9", + "id": "note-ukwn1", "measured": { "height": 630, - "width": 325 + "width": 575 }, "position": { "x": 775.5268622081468, @@ -569,7 +145,7 @@ }, { "data": { - "id": "note-d6QWe", + "id": "note-sQfYZ", "node": { "description": "### 💡 Add your OpenAI API key here👇", "display_name": "", @@ -580,21 +156,22 @@ }, "type": "note" }, - "id": "note-d6QWe", + "dragging": false, + "id": "note-sQfYZ", "measured": { "height": 324, "width": 324 }, "position": { - "x": 1648.6876745095624, - "y": 253.8646618156497 + "x": 1758.8741678279712, + "y": 184.362412184038 }, "selected": false, "type": "noteNode" }, { "data": { - "id": "CalculatorComponent-15FSE", + "id": "CalculatorComponent-Sp3Ca", "node": { "base_classes": [ "Data" @@ -614,7 +191,7 @@ "icon": "calculator", "key": "CalculatorComponent", "legacy": false, - "lf_version": "1.2.0", + "lf_version": "1.4.3", "metadata": {}, "minimized": false, "output_types": [], @@ -623,6 +200,7 @@ "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": false, "method": "to_toolkit", "name": "component_as_tool", @@ -727,9 +305,9 @@ "type": "CalculatorComponent" }, "dragging": false, - "id": "CalculatorComponent-15FSE", + "id": "CalculatorComponent-Sp3Ca", "measured": { - "height": 248, + "height": 217, "width": 320 }, "position": { @@ -741,7 +319,7 @@ }, { "data": { - "id": "ChatInput-2YUmA", + "id": "ChatInput-S6AhV", "node": { "base_classes": [ "Message" @@ -769,6 +347,7 @@ "icon": "MessagesSquare", "key": "ChatInput", "legacy": false, + "lf_version": "1.4.3", "metadata": {}, "minimized": true, "output_types": [], @@ -1041,9 +620,9 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-2YUmA", + "id": "ChatInput-S6AhV", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -1055,7 +634,7 @@ }, { "data": { - "id": "ChatOutput-aHj8n", + "id": "ChatOutput-WciiI", "node": { "base_classes": [ "Message" @@ -1084,6 +663,7 @@ "icon": "MessagesSquare", "key": "ChatOutput", "legacy": false, + "lf_version": "1.4.3", "metadata": {}, "minimized": true, "output_types": [], @@ -1350,9 +930,9 @@ "showNode": false, "type": "ChatOutput" }, - "id": "ChatOutput-aHj8n", + "id": "ChatOutput-WciiI", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -1364,7 +944,7 @@ }, { "data": { - "id": "Agent-qYZ9W", + "id": "Agent-xD3uW", "node": { "base_classes": [ "Message" @@ -1396,7 +976,10 @@ "verbose", "max_iterations", "agent_description", + "mode", + "message", "memory", + "sender_type", "sender", "sender_name", "n_messages", @@ -1409,6 +992,7 @@ "icon": "bot", "key": "Agent", "legacy": false, + "lf_version": "1.4.3", "metadata": {}, "minimized": false, "output_types": [], @@ -1417,8 +1001,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1485,10 +1072,14 @@ "input_types": [], "name": "agent_llm", "options": [ + "Amazon Bedrock", "Anthropic", + "Azure OpenAI", "Google Generative AI", "Groq", + "NVIDIA", "OpenAI", + "SambaNova", "Custom" ], "options_metadata": [ @@ -1542,11 +1133,12 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1709,7 +1301,7 @@ "_input_type": "MessageTextInput", "advanced": true, "display_name": "Message", - "dynamic": false, + "dynamic": true, "info": "The chat message to be stored.", "input_types": [ "Message" @@ -1720,7 +1312,7 @@ "name": "message", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": true, "trace_as_input": true, @@ -1747,7 +1339,7 @@ "tool_mode": false, "trace_as_metadata": true, "type": "tab", - "value": "Store" + "value": "Retrieve" }, "model_kwargs": { "_input_type": "DictInput", @@ -1799,7 +1391,7 @@ "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4.1" + "value": "gpt-4o" }, "n_messages": { "_input_type": "IntInput", @@ -1812,7 +1404,7 @@ "name": "n_messages", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -1881,29 +1473,27 @@ "value": 1 }, "sender": { - "_input_type": "DropdownInput", + "_input_type": "MessageTextInput", "advanced": true, - "combobox": false, - "dialog_inputs": {}, "display_name": "Sender", "dynamic": false, "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" + "input_types": [ + "Message" ], - "options_metadata": [], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "sender", "placeholder": "", "required": false, "show": true, "title_case": false, - "toggle": false, "tool_mode": false, + "trace_as_input": true, "trace_as_metadata": true, "type": "str", - "value": "Machine and User" + "value": "" }, "sender_name": { "_input_type": "MessageTextInput", @@ -1920,7 +1510,7 @@ "name": "sender_name", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -2046,7 +1636,7 @@ "name": "template", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -2113,35 +1703,431 @@ }, "tool_mode": false }, - "selected_output": "response", "showNode": true, "type": "Agent" }, "dragging": false, - "id": "Agent-qYZ9W", + "id": "Agent-xD3uW", "measured": { - "height": 624, + "height": 591, "width": 320 }, "position": { - "x": 1641.6239626366948, - "y": 301.10345101561927 + "x": 1763.0750031786254, + "y": 232.97801992415862 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "URLComponent-6fRXe", + "node": { + "base_classes": [ + "DataFrame", + "Message" + ], + "beta": false, + "category": "data", + "conditional_paths": [], + "custom_fields": {}, + "description": "Fetch content from one or more web pages, following links recursively.", + "display_name": "URL", + "documentation": "", + "edited": false, + "field_order": [ + "urls", + "max_depth", + "prevent_outside", + "use_async", + "format", + "timeout", + "headers", + "filter_text_html", + "continue_on_failure", + "check_response_status", + "autoset_encoding" + ], + "frozen": false, + "icon": "layout-template", + "key": "URLComponent", + "legacy": false, + "lf_version": "1.4.3", + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Toolset", + "group_outputs": false, + "hidden": null, + "method": "to_toolkit", + "name": "component_as_tool", + "options": null, + "required_inputs": null, + "selected": "Tool", + "tool_mode": true, + "types": [ + "Tool" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 2.220446049250313e-16, + "template": { + "_type": "Component", + "autoset_encoding": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Autoset Encoding", + "dynamic": false, + "info": "If enabled, automatically sets the encoding of the request.", + "list": false, + "list_add_label": "Add More", + "name": "autoset_encoding", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "check_response_status": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Check Response Status", + "dynamic": false, + "info": "If enabled, checks the response status of the request.", + "list": false, + "list_add_label": "Add More", + "name": "check_response_status", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "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\nimport requests\nfrom bs4 import BeautifulSoup\nfrom langchain_community.document_loaders import RecursiveUrlLoader\nfrom loguru import logger\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.helpers.data import safe_convert\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SliderInput, TableInput\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.message import Message\nfrom langflow.services.deps import get_settings_service\n\n# Constants\nDEFAULT_TIMEOUT = 30\nDEFAULT_MAX_DEPTH = 1\nDEFAULT_FORMAT = \"Text\"\nURL_REGEX = re.compile(\n r\"^(https?:\\/\\/)?\"\n r\"(www\\.)?\"\n r\"([a-zA-Z0-9.-]+)\"\n r\"(\\.[a-zA-Z]{2,})?\"\n r\"(:\\d+)?\"\n r\"(\\/[^\\s]*)?$\",\n re.IGNORECASE,\n)\n\n\nclass URLComponent(Component):\n \"\"\"A component that loads and parses content from web pages recursively.\n\n This component allows fetching content from one or more URLs, with options to:\n - Control crawl depth\n - Prevent crawling outside the root domain\n - Use async loading for better performance\n - Extract either raw HTML or clean text\n - Configure request headers and timeouts\n \"\"\"\n\n display_name = \"URL\"\n description = \"Fetch content from one or more web pages, following links recursively.\"\n icon = \"layout-template\"\n name = \"URLComponent\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs to crawl recursively, by clicking the '+' button.\",\n is_list=True,\n tool_mode=True,\n placeholder=\"Enter a URL...\",\n list_add_label=\"Add URL\",\n input_types=[],\n ),\n SliderInput(\n name=\"max_depth\",\n display_name=\"Depth\",\n info=(\n \"Controls how many 'clicks' away from the initial page the crawler will go:\\n\"\n \"- depth 1: only the initial page\\n\"\n \"- depth 2: initial page + all pages linked directly from it\\n\"\n \"- depth 3: initial page + direct links + links found on those direct link pages\\n\"\n \"Note: This is about link traversal, not URL path depth.\"\n ),\n value=DEFAULT_MAX_DEPTH,\n range_spec=RangeSpec(min=1, max=5, step=1),\n required=False,\n min_label=\" \",\n max_label=\" \",\n min_label_icon=\"None\",\n max_label_icon=\"None\",\n # slider_input=True\n ),\n BoolInput(\n name=\"prevent_outside\",\n display_name=\"Prevent Outside\",\n info=(\n \"If enabled, only crawls URLs within the same domain as the root URL. \"\n \"This helps prevent the crawler from going to external websites.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"use_async\",\n display_name=\"Use Async\",\n info=(\n \"If enabled, uses asynchronous loading which can be significantly faster \"\n \"but might use more system resources.\"\n ),\n value=True,\n required=False,\n advanced=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 'HTML' for the raw HTML content.\",\n options=[\"Text\", \"HTML\"],\n value=DEFAULT_FORMAT,\n advanced=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout for the request in seconds.\",\n value=DEFAULT_TIMEOUT,\n required=False,\n advanced=True,\n ),\n TableInput(\n name=\"headers\",\n display_name=\"Headers\",\n info=\"The headers to send with the request\",\n table_schema=[\n {\n \"name\": \"key\",\n \"display_name\": \"Header\",\n \"type\": \"str\",\n \"description\": \"Header name\",\n },\n {\n \"name\": \"value\",\n \"display_name\": \"Value\",\n \"type\": \"str\",\n \"description\": \"Header value\",\n },\n ],\n value=[{\"key\": \"User-Agent\", \"value\": get_settings_service().settings.user_agent}],\n advanced=True,\n input_types=[\"DataFrame\"],\n ),\n BoolInput(\n name=\"filter_text_html\",\n display_name=\"Filter Text/HTML\",\n info=\"If enabled, filters out text/css content type from the results.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"continue_on_failure\",\n display_name=\"Continue on Failure\",\n info=\"If enabled, continues crawling even if some requests fail.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"check_response_status\",\n display_name=\"Check Response Status\",\n info=\"If enabled, checks the response status of the request.\",\n value=False,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"autoset_encoding\",\n display_name=\"Autoset Encoding\",\n info=\"If enabled, automatically sets the encoding of the request.\",\n value=True,\n required=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Extracted Pages\", name=\"page_results\", method=\"fetch_content\"),\n Output(display_name=\"Raw Content\", name=\"raw_results\", method=\"fetch_content_as_message\", tool_mode=False),\n ]\n\n @staticmethod\n def validate_url(url: str) -> bool:\n \"\"\"Validates if the given string matches URL pattern.\n\n Args:\n url: The URL string to validate\n\n Returns:\n bool: True if the URL is valid, False otherwise\n \"\"\"\n return bool(URL_REGEX.match(url))\n\n def ensure_url(self, url: str) -> str:\n \"\"\"Ensures the given string is a valid URL.\n\n Args:\n url: The URL string to validate and normalize\n\n Returns:\n str: The normalized URL\n\n Raises:\n ValueError: If the URL is invalid\n \"\"\"\n url = url.strip()\n if not url.startswith((\"http://\", \"https://\")):\n url = \"https://\" + url\n\n if not self.validate_url(url):\n msg = f\"Invalid URL: {url}\"\n raise ValueError(msg)\n\n return url\n\n def _create_loader(self, url: str) -> RecursiveUrlLoader:\n \"\"\"Creates a RecursiveUrlLoader instance with the configured settings.\n\n Args:\n url: The URL to load\n\n Returns:\n RecursiveUrlLoader: Configured loader instance\n \"\"\"\n headers_dict = {header[\"key\"]: header[\"value\"] for header in self.headers}\n extractor = (lambda x: x) if self.format == \"HTML\" else (lambda x: BeautifulSoup(x, \"lxml\").get_text())\n\n return RecursiveUrlLoader(\n url=url,\n max_depth=self.max_depth,\n prevent_outside=self.prevent_outside,\n use_async=self.use_async,\n extractor=extractor,\n timeout=self.timeout,\n headers=headers_dict,\n check_response_status=self.check_response_status,\n continue_on_failure=self.continue_on_failure,\n base_url=url, # Add base_url to ensure consistent domain crawling\n autoset_encoding=self.autoset_encoding, # Enable automatic encoding detection\n exclude_dirs=[], # Allow customization of excluded directories\n link_regex=None, # Allow customization of link filtering\n )\n\n def fetch_url_contents(self) -> list[dict]:\n \"\"\"Load documents from the configured URLs.\n\n Returns:\n List[Data]: List of Data objects containing the fetched content\n\n Raises:\n ValueError: If no valid URLs are provided or if there's an error loading documents\n \"\"\"\n try:\n urls = list({self.ensure_url(url) for url in self.urls if url.strip()})\n logger.info(f\"URLs: {urls}\")\n if not urls:\n msg = \"No valid URLs provided.\"\n raise ValueError(msg)\n\n all_docs = []\n for url in urls:\n logger.info(f\"Loading documents from {url}\")\n\n try:\n loader = self._create_loader(url)\n docs = loader.load()\n\n if not docs:\n logger.warning(f\"No documents found for {url}\")\n continue\n\n logger.info(f\"Found {len(docs)} documents from {url}\")\n all_docs.extend(docs)\n\n except requests.exceptions.RequestException as e:\n logger.exception(f\"Error loading documents from {url}: {e}\")\n continue\n\n if not all_docs:\n msg = \"No documents were successfully loaded from any URL\"\n raise ValueError(msg)\n\n # data = [Data(text=doc.page_content, **doc.metadata) for doc in all_docs]\n data = [\n {\n \"text\": safe_convert(doc.page_content, clean_data=True),\n \"url\": doc.metadata.get(\"source\", \"\"),\n \"title\": doc.metadata.get(\"title\", \"\"),\n \"description\": doc.metadata.get(\"description\", \"\"),\n \"content_type\": doc.metadata.get(\"content_type\", \"\"),\n \"language\": doc.metadata.get(\"language\", \"\"),\n }\n for doc in all_docs\n ]\n except Exception as e:\n error_msg = e.message if hasattr(e, \"message\") else e\n msg = f\"Error loading documents: {error_msg!s}\"\n logger.exception(msg)\n raise ValueError(msg) from e\n return data\n\n def fetch_content(self) -> DataFrame:\n \"\"\"Convert the documents to a DataFrame.\"\"\"\n return DataFrame(data=self.fetch_url_contents())\n\n def fetch_content_as_message(self) -> Message:\n \"\"\"Convert the documents to a Message.\"\"\"\n url_contents = self.fetch_url_contents()\n return Message(text=\"\\n\\n\".join([x[\"text\"] for x in url_contents]), data={\"data\": url_contents})\n" + }, + "continue_on_failure": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Continue on Failure", + "dynamic": false, + "info": "If enabled, continues crawling even if some requests fail.", + "list": false, + "list_add_label": "Add More", + "name": "continue_on_failure", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "filter_text_html": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Filter Text/HTML", + "dynamic": false, + "info": "If enabled, filters out text/css content type from the results.", + "list": false, + "list_add_label": "Add More", + "name": "filter_text_html", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "format": { + "_input_type": "DropdownInput", + "advanced": true, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Output Format", + "dynamic": false, + "info": "Output Format. Use 'Text' to extract the text from the HTML or 'HTML' for the raw HTML content.", + "name": "format", + "options": [ + "Text", + "HTML" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "Text" + }, + "headers": { + "_input_type": "TableInput", + "advanced": true, + "display_name": "Headers", + "dynamic": false, + "info": "The headers to send with the request", + "input_types": [ + "DataFrame" + ], + "is_list": true, + "list_add_label": "Add More", + "name": "headers", + "placeholder": "", + "required": false, + "show": true, + "table_icon": "Table", + "table_schema": { + "columns": [ + { + "default": "None", + "description": "Header name", + "disable_edit": false, + "display_name": "Header", + "edit_mode": "popover", + "filterable": true, + "formatter": "text", + "hidden": false, + "name": "key", + "sortable": true, + "type": "str" + }, + { + "default": "None", + "description": "Header value", + "disable_edit": false, + "display_name": "Value", + "edit_mode": "popover", + "filterable": true, + "formatter": "text", + "hidden": false, + "name": "value", + "sortable": true, + "type": "str" + } + ] + }, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "trigger_icon": "Table", + "trigger_text": "Open table", + "type": "table", + "value": [ + { + "key": "User-Agent", + "value": "langflow" + } + ] + }, + "max_depth": { + "_input_type": "SliderInput", + "advanced": false, + "display_name": "Depth", + "dynamic": false, + "info": "Controls how many 'clicks' away from the initial page the crawler will go:\n- depth 1: only the initial page\n- depth 2: initial page + all pages linked directly from it\n- depth 3: initial page + direct links + links found on those direct link pages\nNote: This is about link traversal, not URL path depth.", + "max_label": " ", + "max_label_icon": "None", + "min_label": " ", + "min_label_icon": "None", + "name": "max_depth", + "placeholder": "", + "range_spec": { + "max": 5, + "min": 1, + "step": 1, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 1 + }, + "prevent_outside": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Prevent Outside", + "dynamic": false, + "info": "If enabled, only crawls URLs within the same domain as the root URL. This helps prevent the crawler from going to external websites.", + "list": false, + "list_add_label": "Add More", + "name": "prevent_outside", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "Timeout for the request in seconds.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 30 + }, + "tools_metadata": { + "_input_type": "ToolsInput", + "advanced": false, + "display_name": "Actions", + "dynamic": false, + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", + "is_list": true, + "list_add_label": "Add More", + "name": "tools_metadata", + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "tools", + "value": [ + { + "args": { + "urls": { + "default": "", + "description": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", + "items": { + "type": "string" + }, + "title": "Urls", + "type": "array" + } + }, + "description": "Fetch content from one or more web pages, following links recursively.", + "display_description": "Fetch content from one or more web pages, following links recursively.", + "display_name": "fetch_content", + "name": "fetch_content", + "readonly": false, + "status": true, + "tags": [ + "fetch_content" + ] + } + ] + }, + "urls": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "URLs", + "dynamic": false, + "info": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", + "input_types": [], + "list": true, + "list_add_label": "Add URL", + "load_from_db": false, + "name": "urls", + "placeholder": "Enter a URL...", + "required": false, + "show": true, + "title_case": false, + "tool_mode": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "use_async": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Use Async", + "dynamic": false, + "info": "If enabled, uses asynchronous loading which can be significantly faster but might use more system resources.", + "list": false, + "list_add_label": "Add More", + "name": "use_async", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + } + }, + "tool_mode": true + }, + "showNode": true, + "type": "URLComponent" + }, + "dragging": false, + "id": "URLComponent-6fRXe", + "measured": { + "height": 289, + "width": 320 + }, + "position": { + "x": 1388.440925896035, + "y": 2.4339723656417362 }, "selected": true, "type": "genericNode" } ], "viewport": { - "x": -343.42019144353594, - "y": 66.6702275988537, - "zoom": 0.5868650751024124 + "x": -398.05374665521265, + "y": 135.56417788603605, + "zoom": 0.5899089629086188 } }, "description": "A simple but powerful starter agent.", "endpoint_name": null, - "id": "85e419cd-33e0-43b7-b5ab-cac101c578f6", + "id": "907853a5-ae9a-4636-b629-4c44cfaf6b85", "is_component": false, - "last_tested_version": "1.3.4", + "last_tested_version": "1.4.3", "name": "Simple Agent", "tags": [ "assistants", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json index 217453213..7297b43cd 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "ApifyActors", - "id": "ApifyActors-CVPGK", + "id": "ApifyActors-I9HDQ", "name": "tool", "output_types": [ "Tool" @@ -15,19 +15,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-yJhxC", + "id": "Agent-wmQQE", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-ApifyActors-CVPGK{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-CVPGKœ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-yJhxC{œfieldNameœ:œtoolsœ,œidœ:œAgent-yJhxCœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "xy-edge__ApifyActors-I9HDQ{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-I9HDQœ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-wmQQE{œfieldNameœ:œtoolsœ,œidœ:œAgent-wmQQEœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "ApifyActors-CVPGK", - "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-CVPGKœ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-yJhxC", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-yJhxCœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "ApifyActors-I9HDQ", + "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-I9HDQœ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-wmQQE", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-wmQQEœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -35,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "ApifyActors", - "id": "ApifyActors-tL94Y", + "id": "ApifyActors-maVx2", "name": "tool", "output_types": [ "Tool" @@ -43,47 +43,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-yJhxC", + "id": "Agent-wmQQE", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-ApifyActors-tL94Y{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-tL94Yœ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-yJhxC{œfieldNameœ:œtoolsœ,œidœ:œAgent-yJhxCœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "xy-edge__ApifyActors-maVx2{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-maVx2œ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-wmQQE{œfieldNameœ:œtoolsœ,œidœ:œAgent-wmQQEœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "ApifyActors-tL94Y", - "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-tL94Yœ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-yJhxC", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-yJhxCœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-E01OU", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-yJhxC", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-E01OU{œdataTypeœ:œChatInputœ,œidœ:œChatInput-E01OUœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-yJhxC{œfieldNameœ:œinput_valueœ,œidœ:œAgent-yJhxCœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-E01OU", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-E01OUœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-yJhxC", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-yJhxCœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ApifyActors-maVx2", + "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-maVx2œ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-wmQQE", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-wmQQEœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -91,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-yJhxC", + "id": "Agent-wmQQE", "name": "response", "output_types": [ "Message" @@ -99,7 +71,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-xSo6b", + "id": "ChatOutput-5yecv", "inputTypes": [ "Data", "DataFrame", @@ -108,18 +80,45 @@ "type": "other" } }, - "id": "reactflow__edge-Agent-yJhxC{œdataTypeœ:œAgentœ,œidœ:œAgent-yJhxCœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-xSo6b{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-xSo6bœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "xy-edge__Agent-wmQQE{œdataTypeœ:œAgentœ,œidœ:œAgent-wmQQEœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-5yecv{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-5yecvœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "Agent-yJhxC", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-yJhxCœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-xSo6b", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-xSo6bœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "Agent-wmQQE", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-wmQQEœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-5yecv", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-5yecvœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-amkkr", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-wmQQE", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__ChatInput-amkkr{œdataTypeœ:œChatInputœ,œidœ:œChatInput-amkkrœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-wmQQE{œfieldNameœ:œinput_valueœ,œidœ:œAgent-wmQQEœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-amkkr", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-amkkrœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-wmQQE", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-wmQQEœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "ApifyActors-tL94Y", + "id": "ApifyActors-I9HDQ", "node": { "base_classes": [ "Data", @@ -308,9 +307,9 @@ "type": "ApifyActors" }, "dragging": false, - "id": "ApifyActors-tL94Y", + "id": "ApifyActors-I9HDQ", "measured": { - "height": 526, + "height": 523, "width": 320 }, "position": { @@ -322,7 +321,7 @@ }, { "data": { - "id": "ApifyActors-CVPGK", + "id": "ApifyActors-maVx2", "node": { "base_classes": [ "Data", @@ -511,9 +510,9 @@ "type": "ApifyActors" }, "dragging": false, - "id": "ApifyActors-CVPGK", + "id": "ApifyActors-maVx2", "measured": { - "height": 526, + "height": 523, "width": 320 }, "position": { @@ -525,7 +524,7 @@ }, { "data": { - "id": "note-hmQk5", + "id": "note-xssJa", "node": { "description": "### 💡 Add your Apify API key here ", "display_name": "", @@ -537,7 +536,7 @@ "type": "note" }, "dragging": false, - "id": "note-hmQk5", + "id": "note-xssJa", "measured": { "height": 324, "width": 324 @@ -551,7 +550,7 @@ }, { "data": { - "id": "note-Utxei", + "id": "note-TeGrW", "node": { "description": "### 💡 Add your Apify API key here ", "display_name": "", @@ -564,7 +563,7 @@ }, "dragging": false, "height": 324, - "id": "note-Utxei", + "id": "note-TeGrW", "measured": { "height": 324, "width": 324 @@ -580,7 +579,7 @@ }, { "data": { - "id": "note-NoZ4e", + "id": "note-6PTdf", "node": { "description": "# Social Media Agent\n\nExtract data with **Apify Actors** and analyze the data with an **Agent**.\n\n## Prerequisites\n\n* An [Apify API token](https://docs.apify.com/platform/integrations/api#api-token)\n* An [OpenAI API key](https://platform.openai.com/)\n\n## Quickstart\n\n1. Enter your **Apify** API token in the **Apify Token** fields of the **Apify Actors** components. \n2. Enter your **OpenAI** API token in the **OpenAI API Key** field of the **Agent** component.\n3. Open the **Playground** and chat with the agent. For example, task it with retrieving a profile bio and the latest video by using this prompt: \n ```\n Find the TikTok profile of the company OpenAI using Google search, then show me the profile bio and their latest video.\n ```", "display_name": "", @@ -593,10 +592,10 @@ }, "dragging": false, "height": 657, - "id": "note-NoZ4e", + "id": "note-6PTdf", "measured": { "height": 657, - "width": 525 + "width": 524 }, "position": { "x": -313.0627945618906, @@ -609,7 +608,7 @@ }, { "data": { - "id": "ChatInput-E01OU", + "id": "ChatInput-amkkr", "node": { "base_classes": [ "Message" @@ -635,7 +634,7 @@ "frozen": false, "icon": "MessagesSquare", "legacy": false, - "lf_version": "1.4.2", + "lf_version": "1.4.3", "metadata": {}, "minimized": true, "output_types": [], @@ -906,7 +905,7 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-E01OU", + "id": "ChatInput-amkkr", "measured": { "height": 48, "width": 192 @@ -920,7 +919,7 @@ }, { "data": { - "id": "ChatOutput-xSo6b", + "id": "ChatOutput-5yecv", "node": { "base_classes": [ "Message" @@ -1214,7 +1213,7 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-xSo6b", + "id": "ChatOutput-5yecv", "measured": { "height": 48, "width": 192 @@ -1228,7 +1227,7 @@ }, { "data": { - "id": "note-kMYOt", + "id": "note-psyK5", "node": { "description": "### 💡 Add your OpenAI API key here ", "display_name": "", @@ -1240,7 +1239,7 @@ "type": "note" }, "dragging": false, - "id": "note-kMYOt", + "id": "note-psyK5", "measured": { "height": 324, "width": 324 @@ -1254,7 +1253,7 @@ }, { "data": { - "id": "Agent-yJhxC", + "id": "Agent-wmQQE", "node": { "base_classes": [ "Message" @@ -1286,7 +1285,10 @@ "verbose", "max_iterations", "agent_description", + "mode", + "message", "memory", + "sender_type", "sender", "sender_name", "n_messages", @@ -1299,7 +1301,6 @@ "icon": "bot", "key": "Agent", "legacy": false, - "lf_version": "1.4.2", "metadata": {}, "minimized": false, "output_types": [], @@ -1308,8 +1309,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1383,30 +1387,18 @@ "Custom" ], "options_metadata": [ - { - "icon": "Amazon" - }, { "icon": "Anthropic" }, - { - "icon": "Azure" - }, { "icon": "GoogleGenerativeAI" }, { "icon": "Groq" }, - { - "icon": "NVIDIA" - }, { "icon": "OpenAI" }, - { - "icon": "SambaNova" - }, { "icon": "brain" } @@ -1416,6 +1408,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1432,6 +1425,7 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, @@ -1599,7 +1593,7 @@ "_input_type": "MessageTextInput", "advanced": true, "display_name": "Message", - "dynamic": false, + "dynamic": true, "info": "The chat message to be stored.", "input_types": [ "Message" @@ -1610,7 +1604,7 @@ "name": "message", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": true, "trace_as_input": true, @@ -1637,7 +1631,7 @@ "tool_mode": false, "trace_as_metadata": true, "type": "tab", - "value": "Store" + "value": "Retrieve" }, "model_kwargs": { "_input_type": "DictInput", @@ -1685,10 +1679,11 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4.1" + "value": "gpt-4o" }, "n_messages": { "_input_type": "IntInput", @@ -1701,7 +1696,7 @@ "name": "n_messages", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -1745,6 +1740,7 @@ "required": true, "show": true, "title_case": false, + "toggle": false, "tool_mode": true, "trace_as_metadata": true, "type": "str", @@ -1769,28 +1765,27 @@ "value": 1 }, "sender": { - "_input_type": "DropdownInput", + "_input_type": "MessageTextInput", "advanced": true, - "combobox": false, - "dialog_inputs": {}, "display_name": "Sender", "dynamic": false, "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" + "input_types": [ + "Message" ], - "options_metadata": [], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "sender", "placeholder": "", "required": false, "show": true, "title_case": false, "tool_mode": false, + "trace_as_input": true, "trace_as_metadata": true, "type": "str", - "value": "Machine and User" + "value": "" }, "sender_name": { "_input_type": "MessageTextInput", @@ -1807,7 +1802,7 @@ "name": "sender_name", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -1933,7 +1928,7 @@ "name": "template", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -2000,35 +1995,34 @@ }, "tool_mode": false }, - "selected_output": "response", "showNode": true, "type": "Agent" }, "dragging": false, - "id": "Agent-yJhxC", + "id": "Agent-wmQQE", "measured": { - "height": 594, + "height": 591, "width": 320 }, "position": { - "x": 1023.5315500182937, - "y": 280.6548808097231 + "x": 1040.7328325813182, + "y": 309.2404087611358 }, - "selected": false, + "selected": true, "type": "genericNode" } ], "viewport": { - "x": 251.14965955941773, - "y": 42.193990847111536, - "zoom": 0.5946080556136385 + "x": -11.680210843338386, + "y": 7.902598790141155, + "zoom": 0.5704013010733382 } }, "description": "Utilize Apify Actors as agent tools to search and analyze social media profiles.", "endpoint_name": null, - "id": "08525bf9-dd32-4bbe-920c-169cffc78890", + "id": "fc6be8ff-289b-43c5-bb7a-35274b5930af", "is_component": false, - "last_tested_version": "1.4.2", + "last_tested_version": "1.4.3", "name": "Social Media Agent", "tags": [ "agent", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json index da963a6ee..b1c57f885 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json @@ -1,41 +1,13 @@ { "data": { "edges": [ - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "SearchComponent", - "id": "SearchComponent-kgsWf", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-H916j", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-SearchComponent-kgsWf{œdataTypeœ:œSearchComponentœ,œidœ:œSearchComponent-kgsWfœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-H916j{œfieldNameœ:œtoolsœ,œidœ:œAgent-H916jœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "SearchComponent-kgsWf", - "sourceHandle": "{œdataTypeœ: œSearchComponentœ, œidœ: œSearchComponent-kgsWfœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-H916j", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-H916jœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, { "animated": false, "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-6dlgJ", + "id": "ChatInput-GQzN9", "name": "message", "output_types": [ "Message" @@ -43,19 +15,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-H916j", + "id": "Agent-SVMdS", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-6dlgJ{œdataTypeœ:œChatInputœ,œidœ:œChatInput-6dlgJœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-H916j{œfieldNameœ:œinput_valueœ,œidœ:œAgent-H916jœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-GQzN9{œdataTypeœ:œChatInputœ,œidœ:œChatInput-GQzN9œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-SVMdS{œfieldNameœ:œinput_valueœ,œidœ:œAgent-SVMdSœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-6dlgJ", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-6dlgJœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-H916j", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-H916jœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-GQzN9", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-GQzN9œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-SVMdS", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-SVMdSœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -63,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-H916j", + "id": "Agent-SVMdS", "name": "response", "output_types": [ "Message" @@ -71,19 +43,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-zFKST", + "id": "Agent-Huf0O", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Agent-H916j{œdataTypeœ:œAgentœ,œidœ:œAgent-H916jœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-zFKST{œfieldNameœ:œinput_valueœ,œidœ:œAgent-zFKSTœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-SVMdS{œdataTypeœ:œAgentœ,œidœ:œAgent-SVMdSœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-Huf0O{œfieldNameœ:œinput_valueœ,œidœ:œAgent-Huf0Oœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-H916j", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-H916jœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-zFKST", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-zFKSTœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-SVMdS", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-SVMdSœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-Huf0O", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-Huf0Oœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -91,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-zFKST", + "id": "Agent-Huf0O", "name": "response", "output_types": [ "Message" @@ -99,19 +71,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-3tuWs", + "id": "Agent-jiGgJ", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Agent-zFKST{œdataTypeœ:œAgentœ,œidœ:œAgent-zFKSTœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-3tuWs{œfieldNameœ:œinput_valueœ,œidœ:œAgent-3tuWsœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-Huf0O{œdataTypeœ:œAgentœ,œidœ:œAgent-Huf0Oœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-jiGgJ{œfieldNameœ:œinput_valueœ,œidœ:œAgent-jiGgJœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-zFKST", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-zFKSTœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-3tuWs", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-3tuWsœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-Huf0O", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-Huf0Oœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-jiGgJ", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-jiGgJœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -119,7 +91,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-3tuWs", + "id": "Agent-jiGgJ", "name": "response", "output_types": [ "Message" @@ -127,7 +99,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-n7Oik", + "id": "ChatOutput-CvvO2", "inputTypes": [ "Data", "DataFrame", @@ -136,19 +108,19 @@ "type": "str" } }, - "id": "reactflow__edge-Agent-3tuWs{œdataTypeœ:œAgentœ,œidœ:œAgent-3tuWsœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-n7Oik{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-n7Oikœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-jiGgJ{œdataTypeœ:œAgentœ,œidœ:œAgent-jiGgJœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-CvvO2{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-CvvO2œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-3tuWs", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-3tuWsœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-n7Oik", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-n7Oikœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-jiGgJ", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-jiGgJœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-CvvO2", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-CvvO2œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, "data": { "sourceHandle": { - "dataType": "URL", - "id": "URL-4LSRv", + "dataType": "SearchComponent", + "id": "SearchComponent-3nVDj", "name": "component_as_tool", "output_types": [ "Tool" @@ -156,26 +128,52 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-zFKST", + "id": "Agent-SVMdS", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__URL-4LSRv{œdataTypeœ:œURLœ,œidœ:œURL-4LSRvœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-zFKST{œfieldNameœ:œtoolsœ,œidœ:œAgent-zFKSTœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "xy-edge__SearchComponent-3nVDj{œdataTypeœ:œSearchComponentœ,œidœ:œSearchComponent-3nVDjœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-SVMdS{œfieldNameœ:œtoolsœ,œidœ:œAgent-SVMdSœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "URL-4LSRv", - "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-4LSRvœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-zFKST", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-zFKSTœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "SearchComponent-3nVDj", + "sourceHandle": "{œdataTypeœ: œSearchComponentœ, œidœ: œSearchComponent-3nVDjœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-SVMdS", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-SVMdSœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, + "data": { + "sourceHandle": { + "dataType": "URLComponent", + "id": "URLComponent-8bgTS", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-Huf0O", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__URLComponent-8bgTS{œdataTypeœ:œURLComponentœ,œidœ:œURLComponent-8bgTSœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-Huf0O{œfieldNameœ:œtoolsœ,œidœ:œAgent-Huf0Oœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "selected": false, + "source": "URLComponent-8bgTS", + "sourceHandle": "{œdataTypeœ: œURLComponentœ, œidœ: œURLComponent-8bgTSœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-Huf0O", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-Huf0Oœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { "data": { "sourceHandle": { "dataType": "CalculatorComponent", - "id": "CalculatorComponent-hlWP4", + "id": "CalculatorComponent-JKeHR", "name": "component_as_tool", "output_types": [ "Tool" @@ -183,25 +181,24 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-3tuWs", + "id": "Agent-jiGgJ", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__CalculatorComponent-hlWP4{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-hlWP4œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-3tuWs{œfieldNameœ:œtoolsœ,œidœ:œAgent-3tuWsœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "CalculatorComponent-hlWP4", - "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-hlWP4œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-3tuWs", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-3tuWsœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "id": "xy-edge__CalculatorComponent-JKeHR{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-JKeHRœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-jiGgJ{œfieldNameœ:œtoolsœ,œidœ:œAgent-jiGgJœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "source": "CalculatorComponent-JKeHR", + "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-JKeHRœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-jiGgJ", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-jiGgJœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-6dlgJ", + "id": "ChatInput-GQzN9", "node": { "base_classes": [ "Message" @@ -475,10 +472,10 @@ }, "dragging": false, "height": 262, - "id": "ChatInput-6dlgJ", + "id": "ChatInput-GQzN9", "measured": { "height": 262, - "width": 320 + "width": 360 }, "position": { "x": 1731.3224944651397, @@ -496,7 +493,7 @@ "data": { "description": "Display a chat message in the Playground.", "display_name": "Chat Output", - "id": "ChatOutput-n7Oik", + "id": "ChatOutput-CvvO2", "node": { "base_classes": [ "Message" @@ -779,10 +776,10 @@ }, "dragging": false, "height": 262, - "id": "ChatOutput-n7Oik", + "id": "ChatOutput-CvvO2", "measured": { "height": 262, - "width": 320 + "width": 360 }, "position": { "x": 4349.229697347143, @@ -798,7 +795,7 @@ }, { "data": { - "id": "note-NwG3w", + "id": "note-CQDFw", "node": { "description": "# Travel Planning Agents \n\nThe travel planning system is a smart setup that uses several specialized \"agents\" to help plan incredible trips. Imagine each agent as a travel expert focusing on a part of your journey. Here's how it works:\n\n- **User-Friendly Start:** You start by telling the system about your travel needs—where you want to go and what you love to do.\n\n- **Data Collection:** The agents uses its tools to gather current info about various destinations, like the best travel times, weather, and costs.\n\n- **Three Key Agents:**\n - **City Selection Agent:** Picks the best places to visit based on your likes and current data.\n - **Local Expert Agent:** Gathers interesting details about what to do and see in the chosen city.\n - **Travel Concierge Agent:** Builds a day-by-day plan that includes where to stay, eat, and explore!\n\n- **Tools and Data:** Each agent uses tools to find and organize the latest information so you get recommendations that are both accurate and exciting.\n\n- **Final Plan:** Once everything is put together, you receive a complete, easy-to-follow travel itinerary, perfect for your adventure!\n", "display_name": "", @@ -809,10 +806,10 @@ }, "dragging": false, "height": 603, - "id": "note-NwG3w", + "id": "note-CQDFw", "measured": { "height": 603, - "width": 325 + "width": 324 }, "position": { "x": 1319.2860379588103, @@ -833,7 +830,7 @@ }, { "data": { - "id": "note-zaSgy", + "id": "note-tuc3p", "node": { "description": "# **City Selection Agent**\n - **Purpose:** This agent evaluates potential travel destinations based on user input and external data sources.\n - **Core Functions:** Analyzes factors such as weather, local events, and travel costs to recommend optimal cities.\n - **Tools Utilized:** Employs APIs and data-fetching tools to gather real-time information for decision-making.\n", "display_name": "", @@ -846,10 +843,10 @@ }, "dragging": false, "height": 334, - "id": "note-zaSgy", + "id": "note-tuc3p", "measured": { "height": 334, - "width": 325 + "width": 324 }, "position": { "x": 2112.2352264274264, @@ -870,7 +867,7 @@ }, { "data": { - "id": "note-imuMP", + "id": "note-68RyJ", "node": { "description": "# **Local Expert Agent**\n - **Purpose:** Focused on gathering and providing an in-depth guide to the selected city.\n - **Core Functions:** Compiles insights into cultural attractions, local customs, and unique experiences.\n - **Tools Utilized:** Uses web content fetchers and data APIs to collect detailed local insights and enhance the user understanding with hidden gems.\n", "display_name": "", @@ -883,10 +880,10 @@ }, "dragging": false, "height": 342, - "id": "note-imuMP", + "id": "note-68RyJ", "measured": { "height": 342, - "width": 325 + "width": 324 }, "position": { "x": 2827.660803823376, @@ -907,7 +904,7 @@ }, { "data": { - "id": "note-KFInF", + "id": "note-2s03A", "node": { "description": "# **Travel Concierge Agent**\n - **Purpose:** Crafts detailed travel itineraries that are customized to the traveler's interests and needs.\n - **Core Functions:** Offers a comprehensive daily schedule, including accommodations, dining spots, and activities.\n - **Tools Utilized:** Integrates calculators and data tools for accurate budget planning and itinerary logistics.", "display_name": "", @@ -920,10 +917,10 @@ }, "dragging": false, "height": 336, - "id": "note-KFInF", + "id": "note-2s03A", "measured": { "height": 336, - "width": 325 + "width": 324 }, "position": { "x": 3536.084279543714, @@ -944,7 +941,7 @@ }, { "data": { - "id": "note-b1zMq", + "id": "note-Qrd85", "node": { "description": "## Configure the agent by obtaining your OpenAI API key from [platform.openai.com](https://platform.openai.com). Under \"Model Provider\", choose:\n- OpenAI: Default, requires only API key\n- Anthropic/Azure/Groq/NVIDIA: Each requires their own API keys\n- Custom: Use your own model endpoint + authentication\n\nSelect model and input API key before running the flow.", "display_name": "", @@ -957,10 +954,10 @@ }, "dragging": false, "height": 324, - "id": "note-b1zMq", + "id": "note-Qrd85", "measured": { "height": 324, - "width": 325 + "width": 324 }, "position": { "x": 2463.3881993480218, @@ -977,860 +974,16 @@ }, { "data": { - "description": "Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "URL", - "id": "URL-4LSRv", - "node": { - "base_classes": [ - "Data", - "DataFrame", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Fetch content from one or more web pages, following links recursively.", - "display_name": "URL", - "documentation": "", - "edited": false, - "field_order": [ - "urls", - "format", - "separator", - "clean_extra_whitespace" - ], - "frozen": false, - "icon": "layout-template", - "legacy": false, - "lf_version": "1.2.0", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "hidden": false, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "autoset_encoding": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Autoset Encoding", - "dynamic": false, - "info": "If enabled, automatically sets the encoding of the request.", - "list": false, - "list_add_label": "Add More", - "name": "autoset_encoding", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "check_response_status": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Check Response Status", - "dynamic": false, - "info": "If enabled, checks the response status of the request.", - "list": false, - "list_add_label": "Add More", - "name": "check_response_status", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "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\nimport requests\nfrom bs4 import BeautifulSoup\nfrom langchain_community.document_loaders import RecursiveUrlLoader\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.helpers.data import safe_convert\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SliderInput, TableInput\nfrom langflow.schema import DataFrame, Message\nfrom langflow.services.deps import get_settings_service\n\n# Constants\nDEFAULT_TIMEOUT = 30\nDEFAULT_MAX_DEPTH = 1\nDEFAULT_FORMAT = \"Text\"\nURL_REGEX = re.compile(\n r\"^(https?:\\/\\/)?\" r\"(www\\.)?\" r\"([a-zA-Z0-9.-]+)\" r\"(\\.[a-zA-Z]{2,})?\" r\"(:\\d+)?\" r\"(\\/[^\\s]*)?$\",\n re.IGNORECASE,\n)\n\n\nclass URLComponent(Component):\n \"\"\"A component that loads and parses content from web pages recursively.\n\n This component allows fetching content from one or more URLs, with options to:\n - Control crawl depth\n - Prevent crawling outside the root domain\n - Use async loading for better performance\n - Extract either raw HTML or clean text\n - Configure request headers and timeouts\n \"\"\"\n\n display_name = \"URL\"\n description = \"Fetch content from one or more web pages, following links recursively.\"\n icon = \"layout-template\"\n name = \"URLComponent\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs to crawl recursively, by clicking the '+' button.\",\n is_list=True,\n tool_mode=True,\n placeholder=\"Enter a URL...\",\n list_add_label=\"Add URL\",\n input_types=[],\n ),\n SliderInput(\n name=\"max_depth\",\n display_name=\"Depth\",\n info=(\n \"Controls how many 'clicks' away from the initial page the crawler will go:\\n\"\n \"- depth 1: only the initial page\\n\"\n \"- depth 2: initial page + all pages linked directly from it\\n\"\n \"- depth 3: initial page + direct links + links found on those direct link pages\\n\"\n \"Note: This is about link traversal, not URL path depth.\"\n ),\n value=DEFAULT_MAX_DEPTH,\n range_spec=RangeSpec(min=1, max=5, step=1),\n required=False,\n min_label=\" \",\n max_label=\" \",\n min_label_icon=\"None\",\n max_label_icon=\"None\",\n # slider_input=True\n ),\n BoolInput(\n name=\"prevent_outside\",\n display_name=\"Prevent Outside\",\n info=(\n \"If enabled, only crawls URLs within the same domain as the root URL. \"\n \"This helps prevent the crawler from going to external websites.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"use_async\",\n display_name=\"Use Async\",\n info=(\n \"If enabled, uses asynchronous loading which can be significantly faster \"\n \"but might use more system resources.\"\n ),\n value=True,\n required=False,\n advanced=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 'HTML' for the raw HTML content.\",\n options=[\"Text\", \"HTML\"],\n value=DEFAULT_FORMAT,\n advanced=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout for the request in seconds.\",\n value=DEFAULT_TIMEOUT,\n required=False,\n advanced=True,\n ),\n TableInput(\n name=\"headers\",\n display_name=\"Headers\",\n info=\"The headers to send with the request\",\n table_schema=[\n {\n \"name\": \"key\",\n \"display_name\": \"Header\",\n \"type\": \"str\",\n \"description\": \"Header name\",\n },\n {\n \"name\": \"value\",\n \"display_name\": \"Value\",\n \"type\": \"str\",\n \"description\": \"Header value\",\n },\n ],\n value=[{\"key\": \"User-Agent\", \"value\": get_settings_service().settings.user_agent}],\n advanced=True,\n input_types=[\"DataFrame\"],\n ),\n BoolInput(\n name=\"filter_text_html\",\n display_name=\"Filter Text/HTML\",\n info=\"If enabled, filters out text/css content type from the results.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"continue_on_failure\",\n display_name=\"Continue on Failure\",\n info=\"If enabled, continues crawling even if some requests fail.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"check_response_status\",\n display_name=\"Check Response Status\",\n info=\"If enabled, checks the response status of the request.\",\n value=False,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"autoset_encoding\",\n display_name=\"Autoset Encoding\",\n info=\"If enabled, automatically sets the encoding of the request.\",\n value=True,\n required=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Result\", name=\"page_results\", method=\"fetch_content\"),\n Output(display_name=\"Raw Result\", name=\"raw_results\", method=\"as_message\"),\n ]\n\n @staticmethod\n def validate_url(url: str) -> bool:\n \"\"\"Validates if the given string matches URL pattern.\n\n Args:\n url: The URL string to validate\n\n Returns:\n bool: True if the URL is valid, False otherwise\n \"\"\"\n return bool(URL_REGEX.match(url))\n\n def ensure_url(self, url: str) -> str:\n \"\"\"Ensures the given string is a valid URL.\n\n Args:\n url: The URL string to validate and normalize\n\n Returns:\n str: The normalized URL\n\n Raises:\n ValueError: If the URL is invalid\n \"\"\"\n url = url.strip()\n if not url.startswith((\"http://\", \"https://\")):\n url = \"https://\" + url\n\n if not self.validate_url(url):\n msg = f\"Invalid URL: {url}\"\n raise ValueError(msg)\n\n return url\n\n def _create_loader(self, url: str) -> RecursiveUrlLoader:\n \"\"\"Creates a RecursiveUrlLoader instance with the configured settings.\n\n Args:\n url: The URL to load\n\n Returns:\n RecursiveUrlLoader: Configured loader instance\n \"\"\"\n headers_dict = {header[\"key\"]: header[\"value\"] for header in self.headers}\n extractor = (lambda x: x) if self.format == \"HTML\" else (lambda x: BeautifulSoup(x, \"lxml\").get_text())\n\n return RecursiveUrlLoader(\n url=url,\n max_depth=self.max_depth,\n prevent_outside=self.prevent_outside,\n use_async=self.use_async,\n extractor=extractor,\n timeout=self.timeout,\n headers=headers_dict,\n check_response_status=self.check_response_status,\n continue_on_failure=self.continue_on_failure,\n base_url=url, # Add base_url to ensure consistent domain crawling\n autoset_encoding=self.autoset_encoding, # Enable automatic encoding detection\n exclude_dirs=[], # Allow customization of excluded directories\n link_regex=None, # Allow customization of link filtering\n )\n\n def fetch_url_contents(self) -> list[dict]:\n \"\"\"Load documents from the configured URLs.\n\n Returns:\n List[Data]: List of Data objects containing the fetched content\n\n Raises:\n ValueError: If no valid URLs are provided or if there's an error loading documents\n \"\"\"\n try:\n urls = list({self.ensure_url(url) for url in self.urls if url.strip()})\n logger.info(f\"URLs: {urls}\")\n if not urls:\n msg = \"No valid URLs provided.\"\n raise ValueError(msg)\n\n all_docs = []\n for url in urls:\n logger.info(f\"Loading documents from {url}\")\n\n try:\n loader = self._create_loader(url)\n docs = loader.load()\n\n if not docs:\n logger.warning(f\"No documents found for {url}\")\n continue\n\n logger.info(f\"Found {len(docs)} documents from {url}\")\n all_docs.extend(docs)\n\n except requests.exceptions.RequestException as e:\n logger.exception(f\"Error loading documents from {url}: {e}\")\n continue\n\n if not all_docs:\n msg = \"No documents were successfully loaded from any URL\"\n raise ValueError(msg)\n\n # data = [Data(text=doc.page_content, **doc.metadata) for doc in all_docs]\n data = [\n {\n \"text\": safe_convert(doc.page_content, clean_data=True),\n \"url\": doc.metadata.get(\"source\", \"\"),\n \"title\": doc.metadata.get(\"title\", \"\"),\n \"description\": doc.metadata.get(\"description\", \"\"),\n \"content_type\": doc.metadata.get(\"content_type\", \"\"),\n \"language\": doc.metadata.get(\"language\", \"\"),\n }\n for doc in all_docs\n ]\n except Exception as e:\n error_msg = e.message if hasattr(e, \"message\") else e\n msg = f\"Error loading documents: {error_msg!s}\"\n logger.exception(msg)\n raise ValueError(msg) from e\n return data\n\n def fetch_content(self) -> DataFrame:\n \"\"\"Convert the documents to a DataFrame.\"\"\"\n return DataFrame(data=self.fetch_url_contents())\n\n def as_message(self) -> Message:\n \"\"\"Convert the documents to a Message.\"\"\"\n url_contents = self.fetch_url_contents()\n return Message(text=\"\\n\\n\".join([x[\"text\"] for x in url_contents]), data={\"data\": url_contents})\n" - }, - "continue_on_failure": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Continue on Failure", - "dynamic": false, - "info": "If enabled, continues crawling even if some requests fail.", - "list": false, - "list_add_label": "Add More", - "name": "continue_on_failure", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "filter_text_html": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Filter Text/HTML", - "dynamic": false, - "info": "If enabled, filters out text/css content type from the results.", - "list": false, - "list_add_label": "Add More", - "name": "filter_text_html", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "format": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Output Format", - "dynamic": false, - "info": "Output Format. Use 'Text' to extract the text from the HTML or 'HTML' for the raw HTML content.", - "name": "format", - "options": [ - "Text", - "HTML" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Text" - }, - "headers": { - "_input_type": "TableInput", - "advanced": true, - "display_name": "Headers", - "dynamic": false, - "info": "The headers to send with the request", - "input_types": [ - "DataFrame" - ], - "is_list": true, - "list_add_label": "Add More", - "name": "headers", - "placeholder": "", - "required": false, - "show": true, - "table_icon": "Table", - "table_schema": { - "columns": [ - { - "default": "None", - "description": "Header name", - "disable_edit": false, - "display_name": "Header", - "edit_mode": "popover", - "filterable": true, - "formatter": "text", - "hidden": false, - "name": "key", - "sortable": true, - "type": "str" - }, - { - "default": "None", - "description": "Header value", - "disable_edit": false, - "display_name": "Value", - "edit_mode": "popover", - "filterable": true, - "formatter": "text", - "hidden": false, - "name": "value", - "sortable": true, - "type": "str" - } - ] - }, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "trigger_icon": "Table", - "trigger_text": "Open table", - "type": "table", - "value": [ - { - "key": "User-Agent", - "value": "langflow" - } - ] - }, - "max_depth": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Depth", - "dynamic": false, - "info": "Controls how many 'clicks' away from the initial page the crawler will go:\n- depth 1: only the initial page\n- depth 2: initial page + all pages linked directly from it\n- depth 3: initial page + direct links + links found on those direct link pages\nNote: This is about link traversal, not URL path depth.", - "max_label": " ", - "max_label_icon": "None", - "min_label": " ", - "min_label_icon": "None", - "name": "max_depth", - "placeholder": "", - "range_spec": { - "max": 5.0, - "min": 1.0, - "step": 1.0, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 1 - }, - "prevent_outside": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Prevent Outside", - "dynamic": false, - "info": "If enabled, only crawls URLs within the same domain as the root URL. This helps prevent the crawler from going to external websites.", - "list": false, - "list_add_label": "Add More", - "name": "prevent_outside", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "Timeout for the request in seconds.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 30 - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": { - "urls": { - "default": "", - "description": "", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "URL. fetch_content() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_description": "URL. fetch_content() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "fetch_content", - "name": "fetch_content", - "status": true, - "tags": [ - "fetch_content" - ] - }, - { - "args": { - "urls": { - "default": "", - "description": "", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "URL. fetch_content_text() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_description": "URL. fetch_content_text() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "fetch_content_text", - "name": "fetch_content_text", - "status": true, - "tags": [ - "fetch_content_text" - ] - }, - { - "args": { - "urls": { - "default": "", - "description": "", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "URL. as_dataframe() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_description": "URL. as_dataframe() - Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", - "display_name": "as_dataframe", - "name": "as_dataframe", - "status": true, - "tags": [ - "as_dataframe" - ] - } - ] - }, - "urls": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "URLs", - "dynamic": false, - "info": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", - "input_types": [], - "list": true, - "list_add_label": "Add URL", - "load_from_db": false, - "name": "urls", - "placeholder": "Enter a URL...", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "use_async": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Use Async", - "dynamic": false, - "info": "If enabled, uses asynchronous loading which can be significantly faster but might use more system resources.", - "list": false, - "list_add_label": "Add More", - "name": "use_async", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": true - }, - "selected_output": "component_as_tool", - "showNode": true, - "type": "URL" - }, - "dragging": false, - "id": "URL-4LSRv", - "measured": { - "height": 523, - "width": 320 - }, - "position": { - "x": 2815.5187953791974, - "y": 949.802524756467 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "CalculatorComponent-hlWP4", - "node": { - "base_classes": [ - "Data" - ], - "beta": false, - "category": "tools", - "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", - "key": "CalculatorComponent", - "legacy": false, - "lf_version": "1.2.0", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "hidden": false, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 0.001, - "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\nfrom collections.abc import Callable\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import MessageTextInput\nfrom langflow.io import Output\nfrom langflow.schema.data import Data\n\n\nclass CalculatorComponent(Component):\n display_name = \"Calculator\"\n description = \"Perform basic arithmetic operations on a given expression.\"\n icon = \"calculator\"\n\n # Cache operators dictionary as a class variable\n OPERATORS: dict[type[ast.operator], Callable] = {\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\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 tool_mode=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"result\", type_=Data, method=\"evaluate_expression\"),\n ]\n\n def _eval_expr(self, node: ast.AST) -> float:\n \"\"\"Evaluate an AST node recursively.\"\"\"\n if isinstance(node, ast.Constant):\n if isinstance(node.value, int | float):\n return float(node.value)\n error_msg = f\"Unsupported constant type: {type(node.value).__name__}\"\n raise TypeError(error_msg)\n if isinstance(node, ast.Num): # For backwards compatibility\n if isinstance(node.n, int | float):\n return float(node.n)\n error_msg = f\"Unsupported number type: {type(node.n).__name__}\"\n raise TypeError(error_msg)\n\n if isinstance(node, ast.BinOp):\n op_type = type(node.op)\n if op_type not in self.OPERATORS:\n error_msg = f\"Unsupported binary operator: {op_type.__name__}\"\n raise TypeError(error_msg)\n\n left = self._eval_expr(node.left)\n right = self._eval_expr(node.right)\n return self.OPERATORS[op_type](left, right)\n\n error_msg = f\"Unsupported operation or expression type: {type(node).__name__}\"\n raise TypeError(error_msg)\n\n def evaluate_expression(self) -> Data:\n \"\"\"Evaluate the mathematical expression and return the result.\"\"\"\n try:\n tree = ast.parse(self.expression, mode=\"eval\")\n result = self._eval_expr(tree.body)\n\n formatted_result = f\"{float(result):.6f}\".rstrip(\"0\").rstrip(\".\")\n self.log(f\"Calculation result: {formatted_result}\")\n\n self.status = formatted_result\n return Data(data={\"result\": formatted_result})\n\n except ZeroDivisionError:\n error_message = \"Error: Division by zero\"\n self.status = error_message\n return Data(data={\"error\": error_message, \"input\": self.expression})\n\n except (SyntaxError, TypeError, KeyError, ValueError, AttributeError, OverflowError) as e:\n error_message = f\"Invalid expression: {e!s}\"\n self.status = error_message\n return Data(data={\"error\": error_message, \"input\": self.expression})\n\n def build(self):\n \"\"\"Return the main evaluation function.\"\"\"\n return self.evaluate_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, - "list_add_label": "Add More", - "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": "" - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": { - "expression": { - "default": "", - "description": "The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').", - "title": "Expression", - "type": "string" - } - }, - "description": "CalculatorComponent. evaluate_expression() - Perform basic arithmetic operations on a given expression.", - "display_description": "CalculatorComponent. evaluate_expression() - Perform basic arithmetic operations on a given expression.", - "display_name": "evaluate_expression", - "name": "evaluate_expression", - "status": true, - "tags": [ - "evaluate_expression" - ] - } - ] - } - }, - "tool_mode": true - }, - "selected_output": "component_as_tool", - "showNode": true, - "type": "CalculatorComponent" - }, - "dragging": false, - "id": "CalculatorComponent-hlWP4", - "measured": { - "height": 248, - "width": 320 - }, - "position": { - "x": 3540.356346381247, - "y": 989.3563951826354 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "description": "Call the searchapi.io API with result limiting", - "display_name": "Search API", - "id": "SearchComponent-kgsWf", - "node": { - "base_classes": [ - "Data", - "DataFrame", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Call the searchapi.io API with result limiting", - "display_name": "Search API", - "documentation": "https://www.searchapi.io/docs/google", - "edited": false, - "field_order": [ - "engine", - "api_key", - "input_value", - "search_params", - "max_results", - "max_snippet_length" - ], - "frozen": false, - "icon": "SearchAPI", - "legacy": false, - "lf_version": "1.2.0", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "hidden": null, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "SearchAPI API Key", - "dynamic": false, - "info": "", - "input_types": [], - "load_from_db": false, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "SEARCHAPI_API_KEY" - }, - "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": "from typing import Any\n\nfrom langchain_community.utilities.searchapi import SearchApiAPIWrapper\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import DictInput, DropdownInput, IntInput, MultilineInput, SecretStrInput\nfrom langflow.io import Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass SearchComponent(Component):\n display_name: str = \"Search API\"\n description: str = \"Call the searchapi.io API with result limiting\"\n documentation: str = \"https://www.searchapi.io/docs/google\"\n icon = \"SearchAPI\"\n\n inputs = [\n DropdownInput(name=\"engine\", display_name=\"Engine\", value=\"google\", options=[\"google\", \"bing\", \"duckduckgo\"]),\n SecretStrInput(name=\"api_key\", display_name=\"SearchAPI API Key\", required=True),\n MultilineInput(\n name=\"input_value\",\n display_name=\"Input\",\n tool_mode=True,\n ),\n DictInput(name=\"search_params\", display_name=\"Search parameters\", advanced=True, is_list=True),\n IntInput(name=\"max_results\", display_name=\"Max Results\", value=5, advanced=True),\n IntInput(name=\"max_snippet_length\", display_name=\"Max Snippet Length\", value=100, advanced=True),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def _build_wrapper(self):\n return SearchApiAPIWrapper(engine=self.engine, searchapi_api_key=self.api_key)\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def fetch_content(self) -> list[Data]:\n wrapper = self._build_wrapper()\n\n def search_func(\n query: str, params: dict[str, Any] | None = None, max_results: int = 5, max_snippet_length: int = 100\n ) -> list[Data]:\n params = params or {}\n full_results = wrapper.results(query=query, **params)\n organic_results = full_results.get(\"organic_results\", [])[:max_results]\n\n return [\n Data(\n text=result.get(\"snippet\", \"\"),\n data={\n \"title\": result.get(\"title\", \"\")[:max_snippet_length],\n \"link\": result.get(\"link\", \"\"),\n \"snippet\": result.get(\"snippet\", \"\")[:max_snippet_length],\n },\n )\n for result in organic_results\n ]\n\n results = search_func(\n self.input_value,\n self.search_params or {},\n self.max_results,\n self.max_snippet_length,\n )\n self.status = results\n return results\n\n def fetch_content_dataframe(self) -> DataFrame:\n \"\"\"Convert the search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.fetch_content()\n return DataFrame(data)\n" - }, - "engine": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Engine", - "dynamic": false, - "info": "", - "name": "engine", - "options": [ - "google", - "bing", - "duckduckgo" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "google" - }, - "input_value": { - "_input_type": "MultilineInput", - "advanced": false, - "copy_field": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "max_results": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Results", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "max_results", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_snippet_length": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Snippet Length", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "max_snippet_length", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "search_params": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Search parameters", - "dynamic": false, - "info": "", - "list": true, - "list_add_label": "Add More", - "name": "search_params", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": {}, - "description": "SearchComponent. fetch_content(SearchComponent. api_key: FieldTypes.TEXT) - Call the searchapi.io API with result limiting", - "display_description": "SearchComponent. fetch_content(SearchComponent. api_key: FieldTypes.TEXT) - Call the searchapi.io API with result limiting", - "display_name": "fetch_content", - "name": "fetch_content", - "status": true, - "tags": [ - "fetch_content" - ] - }, - { - "args": {}, - "description": "SearchComponent. fetch_content_text(SearchComponent. api_key: FieldTypes.TEXT) - Call the searchapi.io API with result limiting", - "display_description": "SearchComponent. fetch_content_text(SearchComponent. api_key: FieldTypes.TEXT) - Call the searchapi.io API with result limiting", - "display_name": "fetch_content_text", - "name": "fetch_content_text", - "status": true, - "tags": [ - "fetch_content_text" - ] - }, - { - "args": {}, - "description": "SearchComponent. as_dataframe(SearchComponent. api_key: FieldTypes.TEXT) - Call the searchapi.io API with result limiting", - "display_description": "SearchComponent. as_dataframe(SearchComponent. api_key: FieldTypes.TEXT) - Call the searchapi.io API with result limiting", - "display_name": "as_dataframe", - "name": "as_dataframe", - "status": true, - "tags": [ - "as_dataframe" - ] - } - ] - } - }, - "tool_mode": true - }, - "selected_output": "component_as_tool", - "showNode": true, - "type": "SearchComponent" - }, - "dragging": false, - "id": "SearchComponent-kgsWf", - "measured": { - "height": 421, - "width": 320 - }, - "position": { - "x": 2089.0393126914205, - "y": 894.9349094163676 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Agent-H916j", + "id": "Agent-SVMdS", "node": { "base_classes": [ "Message" ], "beta": false, - "category": "agents", "conditional_paths": [], "custom_fields": {}, "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "City Selection Agent", + "display_name": "Agent", "documentation": "", "edited": false, "field_order": [ @@ -1852,7 +1005,10 @@ "verbose", "max_iterations", "agent_description", + "mode", + "message", "memory", + "sender_type", "sender", "sender_name", "n_messages", @@ -1863,9 +1019,7 @@ ], "frozen": false, "icon": "bot", - "key": "Agent", "legacy": false, - "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -1874,8 +1028,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1885,7 +1042,6 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -1942,37 +1098,29 @@ "input_types": [], "name": "agent_llm", "options": [ + "Amazon Bedrock", "Anthropic", + "Azure OpenAI", "Google Generative AI", "Groq", + "NVIDIA", "OpenAI", + "SambaNova", "Custom" ], "options_metadata": [ - { - "icon": "Amazon" - }, { "icon": "Anthropic" }, - { - "icon": "Azure" - }, { "icon": "GoogleGenerativeAI" }, { "icon": "Groq" }, - { - "icon": "NVIDIA" - }, { "icon": "OpenAI" }, - { - "icon": "SambaNova" - }, { "icon": "brain" } @@ -1982,6 +1130,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1998,11 +1147,12 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -2165,7 +1315,7 @@ "_input_type": "MessageTextInput", "advanced": true, "display_name": "Message", - "dynamic": false, + "dynamic": true, "info": "The chat message to be stored.", "input_types": [ "Message" @@ -2176,7 +1326,7 @@ "name": "message", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": true, "trace_as_input": true, @@ -2190,6 +1340,7 @@ "display_name": "Mode", "dynamic": false, "info": "Operation mode: Store messages or Retrieve messages.", + "load_from_db": false, "name": "mode", "options": [ "Retrieve", @@ -2231,6 +1382,7 @@ "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -2251,6 +1403,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -2267,7 +1420,7 @@ "name": "n_messages", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -2311,6 +1464,7 @@ "required": true, "show": true, "title_case": false, + "toggle": false, "tool_mode": true, "trace_as_metadata": true, "type": "str", @@ -2335,25 +1489,24 @@ "value": 1 }, "sender": { - "_input_type": "DropdownInput", + "_input_type": "MessageTextInput", "advanced": true, - "combobox": false, - "dialog_inputs": {}, "display_name": "Sender", "dynamic": false, "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" + "input_types": [ + "Message" ], - "options_metadata": [], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "sender", "placeholder": "", "required": false, "show": true, "title_case": false, "tool_mode": false, + "trace_as_input": true, "trace_as_metadata": true, "type": "str", "value": "Machine and User" @@ -2373,7 +1526,7 @@ "name": "sender_name", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -2499,7 +1652,7 @@ "name": "template", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -2571,9 +1724,9 @@ "type": "Agent" }, "dragging": false, - "id": "Agent-H916j", + "id": "Agent-SVMdS", "measured": { - "height": 624, + "height": 591, "width": 320 }, "position": { @@ -2585,17 +1738,16 @@ }, { "data": { - "id": "Agent-zFKST", + "id": "Agent-Huf0O", "node": { "base_classes": [ "Message" ], "beta": false, - "category": "agents", "conditional_paths": [], "custom_fields": {}, "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Local Expert Agent", + "display_name": "Agent", "documentation": "", "edited": false, "field_order": [ @@ -2617,7 +1769,10 @@ "verbose", "max_iterations", "agent_description", + "mode", + "message", "memory", + "sender_type", "sender", "sender_name", "n_messages", @@ -2628,9 +1783,7 @@ ], "frozen": false, "icon": "bot", - "key": "Agent", "legacy": false, - "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -2639,8 +1792,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -2650,7 +1806,6 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -2707,37 +1862,29 @@ "input_types": [], "name": "agent_llm", "options": [ + "Amazon Bedrock", "Anthropic", + "Azure OpenAI", "Google Generative AI", "Groq", + "NVIDIA", "OpenAI", + "SambaNova", "Custom" ], "options_metadata": [ - { - "icon": "Amazon" - }, { "icon": "Anthropic" }, - { - "icon": "Azure" - }, { "icon": "GoogleGenerativeAI" }, { "icon": "Groq" }, - { - "icon": "NVIDIA" - }, { "icon": "OpenAI" }, - { - "icon": "SambaNova" - }, { "icon": "brain" } @@ -2747,6 +1894,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -2763,11 +1911,12 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -2930,7 +2079,7 @@ "_input_type": "MessageTextInput", "advanced": true, "display_name": "Message", - "dynamic": false, + "dynamic": true, "info": "The chat message to be stored.", "input_types": [ "Message" @@ -2941,7 +2090,7 @@ "name": "message", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": true, "trace_as_input": true, @@ -2955,6 +2104,7 @@ "display_name": "Mode", "dynamic": false, "info": "Operation mode: Store messages or Retrieve messages.", + "load_from_db": false, "name": "mode", "options": [ "Retrieve", @@ -2996,6 +2146,7 @@ "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -3016,6 +2167,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -3032,7 +2184,7 @@ "name": "n_messages", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -3076,6 +2228,7 @@ "required": true, "show": true, "title_case": false, + "toggle": false, "tool_mode": true, "trace_as_metadata": true, "type": "str", @@ -3100,25 +2253,24 @@ "value": 1 }, "sender": { - "_input_type": "DropdownInput", + "_input_type": "MessageTextInput", "advanced": true, - "combobox": false, - "dialog_inputs": {}, "display_name": "Sender", "dynamic": false, "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" + "input_types": [ + "Message" ], - "options_metadata": [], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "sender", "placeholder": "", "required": false, "show": true, "title_case": false, "tool_mode": false, + "trace_as_input": true, "trace_as_metadata": true, "type": "str", "value": "Machine and User" @@ -3138,7 +2290,7 @@ "name": "sender_name", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -3264,7 +2416,7 @@ "name": "template", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -3336,9 +2488,9 @@ "type": "Agent" }, "dragging": false, - "id": "Agent-zFKST", + "id": "Agent-Huf0O", "measured": { - "height": 624, + "height": 591, "width": 320 }, "position": { @@ -3350,17 +2502,16 @@ }, { "data": { - "id": "Agent-3tuWs", + "id": "Agent-jiGgJ", "node": { "base_classes": [ "Message" ], "beta": false, - "category": "agents", "conditional_paths": [], "custom_fields": {}, "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Travel Concierge Agent", + "display_name": "Agent", "documentation": "", "edited": false, "field_order": [ @@ -3382,7 +2533,10 @@ "verbose", "max_iterations", "agent_description", + "mode", + "message", "memory", + "sender_type", "sender", "sender_name", "n_messages", @@ -3393,9 +2547,7 @@ ], "frozen": false, "icon": "bot", - "key": "Agent", "legacy": false, - "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -3404,8 +2556,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -3415,7 +2570,6 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -3472,37 +2626,29 @@ "input_types": [], "name": "agent_llm", "options": [ + "Amazon Bedrock", "Anthropic", + "Azure OpenAI", "Google Generative AI", "Groq", + "NVIDIA", "OpenAI", + "SambaNova", "Custom" ], "options_metadata": [ - { - "icon": "Amazon" - }, { "icon": "Anthropic" }, - { - "icon": "Azure" - }, { "icon": "GoogleGenerativeAI" }, { "icon": "Groq" }, - { - "icon": "NVIDIA" - }, { "icon": "OpenAI" }, - { - "icon": "SambaNova" - }, { "icon": "brain" } @@ -3512,6 +2658,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -3528,11 +2675,12 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -3695,7 +2843,7 @@ "_input_type": "MessageTextInput", "advanced": true, "display_name": "Message", - "dynamic": false, + "dynamic": true, "info": "The chat message to be stored.", "input_types": [ "Message" @@ -3706,7 +2854,7 @@ "name": "message", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": true, "trace_as_input": true, @@ -3720,6 +2868,7 @@ "display_name": "Mode", "dynamic": false, "info": "Operation mode: Store messages or Retrieve messages.", + "load_from_db": false, "name": "mode", "options": [ "Retrieve", @@ -3761,6 +2910,7 @@ "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -3781,6 +2931,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -3797,7 +2948,7 @@ "name": "n_messages", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -3841,6 +2992,7 @@ "required": true, "show": true, "title_case": false, + "toggle": false, "tool_mode": true, "trace_as_metadata": true, "type": "str", @@ -3865,25 +3017,24 @@ "value": 1 }, "sender": { - "_input_type": "DropdownInput", + "_input_type": "MessageTextInput", "advanced": true, - "combobox": false, - "dialog_inputs": {}, "display_name": "Sender", "dynamic": false, "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" + "input_types": [ + "Message" ], - "options_metadata": [], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "sender", "placeholder": "", "required": false, "show": true, "title_case": false, "tool_mode": false, + "trace_as_input": true, "trace_as_metadata": true, "type": "str", "value": "Machine and User" @@ -3903,7 +3054,7 @@ "name": "sender_name", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -4029,7 +3180,7 @@ "name": "template", "placeholder": "", "required": false, - "show": true, + "show": false, "title_case": false, "tool_mode": false, "trace_as_input": true, @@ -4101,30 +3252,823 @@ "type": "Agent" }, "dragging": false, - "id": "Agent-3tuWs", + "id": "Agent-jiGgJ", "measured": { - "height": 624, + "height": 591, "width": 320 }, "position": { "x": 3936.123532016018, "y": 356.3534774464019 }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "SearchComponent-3nVDj", + "node": { + "base_classes": [ + "DataFrame" + ], + "beta": false, + "category": "search", + "conditional_paths": [], + "custom_fields": {}, + "description": "Call the searchapi.io API with result limiting", + "display_name": "Search API", + "documentation": "https://www.searchapi.io/docs/google", + "edited": false, + "field_order": [ + "engine", + "api_key", + "input_value", + "search_params", + "max_results", + "max_snippet_length" + ], + "frozen": false, + "icon": "SearchAPI", + "key": "SearchComponent", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Toolset", + "group_outputs": false, + "hidden": null, + "method": "to_toolkit", + "name": "component_as_tool", + "options": null, + "required_inputs": null, + "selected": "Tool", + "tool_mode": true, + "types": [ + "Tool" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 4.574062563799057e-12, + "template": { + "_type": "Component", + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "SearchAPI API Key", + "dynamic": false, + "info": "", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "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": "from typing import Any\n\nfrom langchain_community.utilities.searchapi import SearchApiAPIWrapper\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import DictInput, DropdownInput, IntInput, MultilineInput, SecretStrInput\nfrom langflow.io import Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass SearchComponent(Component):\n display_name: str = \"Search API\"\n description: str = \"Call the searchapi.io API with result limiting\"\n documentation: str = \"https://www.searchapi.io/docs/google\"\n icon = \"SearchAPI\"\n\n inputs = [\n DropdownInput(name=\"engine\", display_name=\"Engine\", value=\"google\", options=[\"google\", \"bing\", \"duckduckgo\"]),\n SecretStrInput(name=\"api_key\", display_name=\"SearchAPI API Key\", required=True),\n MultilineInput(\n name=\"input_value\",\n display_name=\"Input\",\n tool_mode=True,\n ),\n DictInput(name=\"search_params\", display_name=\"Search parameters\", advanced=True, is_list=True),\n IntInput(name=\"max_results\", display_name=\"Max Results\", value=5, advanced=True),\n IntInput(name=\"max_snippet_length\", display_name=\"Max Snippet Length\", value=100, advanced=True),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def _build_wrapper(self):\n return SearchApiAPIWrapper(engine=self.engine, searchapi_api_key=self.api_key)\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def fetch_content(self) -> list[Data]:\n wrapper = self._build_wrapper()\n\n def search_func(\n query: str, params: dict[str, Any] | None = None, max_results: int = 5, max_snippet_length: int = 100\n ) -> list[Data]:\n params = params or {}\n full_results = wrapper.results(query=query, **params)\n organic_results = full_results.get(\"organic_results\", [])[:max_results]\n\n return [\n Data(\n text=result.get(\"snippet\", \"\"),\n data={\n \"title\": result.get(\"title\", \"\")[:max_snippet_length],\n \"link\": result.get(\"link\", \"\"),\n \"snippet\": result.get(\"snippet\", \"\")[:max_snippet_length],\n },\n )\n for result in organic_results\n ]\n\n results = search_func(\n self.input_value,\n self.search_params or {},\n self.max_results,\n self.max_snippet_length,\n )\n self.status = results\n return results\n\n def fetch_content_dataframe(self) -> DataFrame:\n \"\"\"Convert the search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.fetch_content()\n return DataFrame(data)\n" + }, + "engine": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Engine", + "dynamic": false, + "info": "", + "name": "engine", + "options": [ + "google", + "bing", + "duckduckgo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "google" + }, + "input_value": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "max_results": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Results", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "max_results", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_snippet_length": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Snippet Length", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "max_snippet_length", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "search_params": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Search parameters", + "dynamic": false, + "info": "", + "list": true, + "list_add_label": "Add More", + "name": "search_params", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "tools_metadata": { + "_input_type": "ToolsInput", + "advanced": false, + "display_name": "Actions", + "dynamic": false, + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", + "is_list": true, + "list_add_label": "Add More", + "name": "tools_metadata", + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "tools", + "value": [ + { + "args": { + "input_value": { + "default": "", + "description": "", + "title": "Input Value", + "type": "string" + } + }, + "description": "Call the searchapi.io API with result limiting", + "display_description": "Call the searchapi.io API with result limiting", + "display_name": "fetch_content_dataframe", + "name": "fetch_content_dataframe", + "readonly": false, + "status": true, + "tags": [ + "fetch_content_dataframe" + ] + } + ] + } + }, + "tool_mode": true + }, + "showNode": true, + "type": "SearchComponent" + }, + "dragging": false, + "id": "SearchComponent-3nVDj", + "measured": { + "height": 365, + "width": 320 + }, + "position": { + "x": 2093.1263360559856, + "y": 887.965322905591 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "URLComponent-8bgTS", + "node": { + "base_classes": [ + "DataFrame", + "Message" + ], + "beta": false, + "category": "data", + "conditional_paths": [], + "custom_fields": {}, + "description": "Fetch content from one or more web pages, following links recursively.", + "display_name": "URL", + "documentation": "", + "edited": false, + "field_order": [ + "urls", + "max_depth", + "prevent_outside", + "use_async", + "format", + "timeout", + "headers", + "filter_text_html", + "continue_on_failure", + "check_response_status", + "autoset_encoding" + ], + "frozen": false, + "icon": "layout-template", + "key": "URLComponent", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Toolset", + "group_outputs": false, + "hidden": null, + "method": "to_toolkit", + "name": "component_as_tool", + "options": null, + "required_inputs": null, + "selected": "Tool", + "tool_mode": true, + "types": [ + "Tool" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 2.220446049250313e-16, + "template": { + "_type": "Component", + "autoset_encoding": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Autoset Encoding", + "dynamic": false, + "info": "If enabled, automatically sets the encoding of the request.", + "list": false, + "list_add_label": "Add More", + "name": "autoset_encoding", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "check_response_status": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Check Response Status", + "dynamic": false, + "info": "If enabled, checks the response status of the request.", + "list": false, + "list_add_label": "Add More", + "name": "check_response_status", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "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\nimport requests\nfrom bs4 import BeautifulSoup\nfrom langchain_community.document_loaders import RecursiveUrlLoader\nfrom loguru import logger\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.helpers.data import safe_convert\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SliderInput, TableInput\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.message import Message\nfrom langflow.services.deps import get_settings_service\n\n# Constants\nDEFAULT_TIMEOUT = 30\nDEFAULT_MAX_DEPTH = 1\nDEFAULT_FORMAT = \"Text\"\nURL_REGEX = re.compile(\n r\"^(https?:\\/\\/)?\"\n r\"(www\\.)?\"\n r\"([a-zA-Z0-9.-]+)\"\n r\"(\\.[a-zA-Z]{2,})?\"\n r\"(:\\d+)?\"\n r\"(\\/[^\\s]*)?$\",\n re.IGNORECASE,\n)\n\n\nclass URLComponent(Component):\n \"\"\"A component that loads and parses content from web pages recursively.\n\n This component allows fetching content from one or more URLs, with options to:\n - Control crawl depth\n - Prevent crawling outside the root domain\n - Use async loading for better performance\n - Extract either raw HTML or clean text\n - Configure request headers and timeouts\n \"\"\"\n\n display_name = \"URL\"\n description = \"Fetch content from one or more web pages, following links recursively.\"\n icon = \"layout-template\"\n name = \"URLComponent\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs to crawl recursively, by clicking the '+' button.\",\n is_list=True,\n tool_mode=True,\n placeholder=\"Enter a URL...\",\n list_add_label=\"Add URL\",\n input_types=[],\n ),\n SliderInput(\n name=\"max_depth\",\n display_name=\"Depth\",\n info=(\n \"Controls how many 'clicks' away from the initial page the crawler will go:\\n\"\n \"- depth 1: only the initial page\\n\"\n \"- depth 2: initial page + all pages linked directly from it\\n\"\n \"- depth 3: initial page + direct links + links found on those direct link pages\\n\"\n \"Note: This is about link traversal, not URL path depth.\"\n ),\n value=DEFAULT_MAX_DEPTH,\n range_spec=RangeSpec(min=1, max=5, step=1),\n required=False,\n min_label=\" \",\n max_label=\" \",\n min_label_icon=\"None\",\n max_label_icon=\"None\",\n # slider_input=True\n ),\n BoolInput(\n name=\"prevent_outside\",\n display_name=\"Prevent Outside\",\n info=(\n \"If enabled, only crawls URLs within the same domain as the root URL. \"\n \"This helps prevent the crawler from going to external websites.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"use_async\",\n display_name=\"Use Async\",\n info=(\n \"If enabled, uses asynchronous loading which can be significantly faster \"\n \"but might use more system resources.\"\n ),\n value=True,\n required=False,\n advanced=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 'HTML' for the raw HTML content.\",\n options=[\"Text\", \"HTML\"],\n value=DEFAULT_FORMAT,\n advanced=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout for the request in seconds.\",\n value=DEFAULT_TIMEOUT,\n required=False,\n advanced=True,\n ),\n TableInput(\n name=\"headers\",\n display_name=\"Headers\",\n info=\"The headers to send with the request\",\n table_schema=[\n {\n \"name\": \"key\",\n \"display_name\": \"Header\",\n \"type\": \"str\",\n \"description\": \"Header name\",\n },\n {\n \"name\": \"value\",\n \"display_name\": \"Value\",\n \"type\": \"str\",\n \"description\": \"Header value\",\n },\n ],\n value=[{\"key\": \"User-Agent\", \"value\": get_settings_service().settings.user_agent}],\n advanced=True,\n input_types=[\"DataFrame\"],\n ),\n BoolInput(\n name=\"filter_text_html\",\n display_name=\"Filter Text/HTML\",\n info=\"If enabled, filters out text/css content type from the results.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"continue_on_failure\",\n display_name=\"Continue on Failure\",\n info=\"If enabled, continues crawling even if some requests fail.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"check_response_status\",\n display_name=\"Check Response Status\",\n info=\"If enabled, checks the response status of the request.\",\n value=False,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"autoset_encoding\",\n display_name=\"Autoset Encoding\",\n info=\"If enabled, automatically sets the encoding of the request.\",\n value=True,\n required=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Extracted Pages\", name=\"page_results\", method=\"fetch_content\"),\n Output(display_name=\"Raw Content\", name=\"raw_results\", method=\"fetch_content_as_message\", tool_mode=False),\n ]\n\n @staticmethod\n def validate_url(url: str) -> bool:\n \"\"\"Validates if the given string matches URL pattern.\n\n Args:\n url: The URL string to validate\n\n Returns:\n bool: True if the URL is valid, False otherwise\n \"\"\"\n return bool(URL_REGEX.match(url))\n\n def ensure_url(self, url: str) -> str:\n \"\"\"Ensures the given string is a valid URL.\n\n Args:\n url: The URL string to validate and normalize\n\n Returns:\n str: The normalized URL\n\n Raises:\n ValueError: If the URL is invalid\n \"\"\"\n url = url.strip()\n if not url.startswith((\"http://\", \"https://\")):\n url = \"https://\" + url\n\n if not self.validate_url(url):\n msg = f\"Invalid URL: {url}\"\n raise ValueError(msg)\n\n return url\n\n def _create_loader(self, url: str) -> RecursiveUrlLoader:\n \"\"\"Creates a RecursiveUrlLoader instance with the configured settings.\n\n Args:\n url: The URL to load\n\n Returns:\n RecursiveUrlLoader: Configured loader instance\n \"\"\"\n headers_dict = {header[\"key\"]: header[\"value\"] for header in self.headers}\n extractor = (lambda x: x) if self.format == \"HTML\" else (lambda x: BeautifulSoup(x, \"lxml\").get_text())\n\n return RecursiveUrlLoader(\n url=url,\n max_depth=self.max_depth,\n prevent_outside=self.prevent_outside,\n use_async=self.use_async,\n extractor=extractor,\n timeout=self.timeout,\n headers=headers_dict,\n check_response_status=self.check_response_status,\n continue_on_failure=self.continue_on_failure,\n base_url=url, # Add base_url to ensure consistent domain crawling\n autoset_encoding=self.autoset_encoding, # Enable automatic encoding detection\n exclude_dirs=[], # Allow customization of excluded directories\n link_regex=None, # Allow customization of link filtering\n )\n\n def fetch_url_contents(self) -> list[dict]:\n \"\"\"Load documents from the configured URLs.\n\n Returns:\n List[Data]: List of Data objects containing the fetched content\n\n Raises:\n ValueError: If no valid URLs are provided or if there's an error loading documents\n \"\"\"\n try:\n urls = list({self.ensure_url(url) for url in self.urls if url.strip()})\n logger.info(f\"URLs: {urls}\")\n if not urls:\n msg = \"No valid URLs provided.\"\n raise ValueError(msg)\n\n all_docs = []\n for url in urls:\n logger.info(f\"Loading documents from {url}\")\n\n try:\n loader = self._create_loader(url)\n docs = loader.load()\n\n if not docs:\n logger.warning(f\"No documents found for {url}\")\n continue\n\n logger.info(f\"Found {len(docs)} documents from {url}\")\n all_docs.extend(docs)\n\n except requests.exceptions.RequestException as e:\n logger.exception(f\"Error loading documents from {url}: {e}\")\n continue\n\n if not all_docs:\n msg = \"No documents were successfully loaded from any URL\"\n raise ValueError(msg)\n\n # data = [Data(text=doc.page_content, **doc.metadata) for doc in all_docs]\n data = [\n {\n \"text\": safe_convert(doc.page_content, clean_data=True),\n \"url\": doc.metadata.get(\"source\", \"\"),\n \"title\": doc.metadata.get(\"title\", \"\"),\n \"description\": doc.metadata.get(\"description\", \"\"),\n \"content_type\": doc.metadata.get(\"content_type\", \"\"),\n \"language\": doc.metadata.get(\"language\", \"\"),\n }\n for doc in all_docs\n ]\n except Exception as e:\n error_msg = e.message if hasattr(e, \"message\") else e\n msg = f\"Error loading documents: {error_msg!s}\"\n logger.exception(msg)\n raise ValueError(msg) from e\n return data\n\n def fetch_content(self) -> DataFrame:\n \"\"\"Convert the documents to a DataFrame.\"\"\"\n return DataFrame(data=self.fetch_url_contents())\n\n def fetch_content_as_message(self) -> Message:\n \"\"\"Convert the documents to a Message.\"\"\"\n url_contents = self.fetch_url_contents()\n return Message(text=\"\\n\\n\".join([x[\"text\"] for x in url_contents]), data={\"data\": url_contents})\n" + }, + "continue_on_failure": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Continue on Failure", + "dynamic": false, + "info": "If enabled, continues crawling even if some requests fail.", + "list": false, + "list_add_label": "Add More", + "name": "continue_on_failure", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "filter_text_html": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Filter Text/HTML", + "dynamic": false, + "info": "If enabled, filters out text/css content type from the results.", + "list": false, + "list_add_label": "Add More", + "name": "filter_text_html", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "format": { + "_input_type": "DropdownInput", + "advanced": true, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Output Format", + "dynamic": false, + "info": "Output Format. Use 'Text' to extract the text from the HTML or 'HTML' for the raw HTML content.", + "name": "format", + "options": [ + "Text", + "HTML" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "Text" + }, + "headers": { + "_input_type": "TableInput", + "advanced": true, + "display_name": "Headers", + "dynamic": false, + "info": "The headers to send with the request", + "input_types": [ + "DataFrame" + ], + "is_list": true, + "list_add_label": "Add More", + "name": "headers", + "placeholder": "", + "required": false, + "show": true, + "table_icon": "Table", + "table_schema": { + "columns": [ + { + "default": "None", + "description": "Header name", + "disable_edit": false, + "display_name": "Header", + "edit_mode": "popover", + "filterable": true, + "formatter": "text", + "hidden": false, + "name": "key", + "sortable": true, + "type": "str" + }, + { + "default": "None", + "description": "Header value", + "disable_edit": false, + "display_name": "Value", + "edit_mode": "popover", + "filterable": true, + "formatter": "text", + "hidden": false, + "name": "value", + "sortable": true, + "type": "str" + } + ] + }, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "trigger_icon": "Table", + "trigger_text": "Open table", + "type": "table", + "value": [ + { + "key": "User-Agent", + "value": "langflow" + } + ] + }, + "max_depth": { + "_input_type": "SliderInput", + "advanced": false, + "display_name": "Depth", + "dynamic": false, + "info": "Controls how many 'clicks' away from the initial page the crawler will go:\n- depth 1: only the initial page\n- depth 2: initial page + all pages linked directly from it\n- depth 3: initial page + direct links + links found on those direct link pages\nNote: This is about link traversal, not URL path depth.", + "max_label": " ", + "max_label_icon": "None", + "min_label": " ", + "min_label_icon": "None", + "name": "max_depth", + "placeholder": "", + "range_spec": { + "max": 5, + "min": 1, + "step": 1, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 1 + }, + "prevent_outside": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Prevent Outside", + "dynamic": false, + "info": "If enabled, only crawls URLs within the same domain as the root URL. This helps prevent the crawler from going to external websites.", + "list": false, + "list_add_label": "Add More", + "name": "prevent_outside", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "Timeout for the request in seconds.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 30 + }, + "tools_metadata": { + "_input_type": "ToolsInput", + "advanced": false, + "display_name": "Actions", + "dynamic": false, + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", + "is_list": true, + "list_add_label": "Add More", + "name": "tools_metadata", + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "tools", + "value": [ + { + "args": { + "urls": { + "default": "", + "description": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", + "items": { + "type": "string" + }, + "title": "Urls", + "type": "array" + } + }, + "description": "Fetch content from one or more web pages, following links recursively.", + "display_description": "Fetch content from one or more web pages, following links recursively.", + "display_name": "fetch_content", + "name": "fetch_content", + "readonly": false, + "status": true, + "tags": [ + "fetch_content" + ] + } + ] + }, + "urls": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "URLs", + "dynamic": false, + "info": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", + "input_types": [], + "list": true, + "list_add_label": "Add URL", + "load_from_db": false, + "name": "urls", + "placeholder": "Enter a URL...", + "required": false, + "show": true, + "title_case": false, + "tool_mode": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "use_async": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Use Async", + "dynamic": false, + "info": "If enabled, uses asynchronous loading which can be significantly faster but might use more system resources.", + "list": false, + "list_add_label": "Add More", + "name": "use_async", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + } + }, + "tool_mode": true + }, + "showNode": true, + "type": "URLComponent" + }, + "dragging": false, + "id": "URLComponent-8bgTS", + "measured": { + "height": 289, + "width": 320 + }, + "position": { + "x": 2713.896825977834, + "y": 998.9242993650518 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "CalculatorComponent-JKeHR", + "node": { + "base_classes": [ + "Data" + ], + "beta": false, + "category": "helpers", + "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", + "key": "CalculatorComponent", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Toolset", + "group_outputs": false, + "hidden": null, + "method": "to_toolkit", + "name": "component_as_tool", + "options": null, + "required_inputs": null, + "selected": "Tool", + "tool_mode": true, + "types": [ + "Tool" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 0.001, + "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\nfrom collections.abc import Callable\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import MessageTextInput\nfrom langflow.io import Output\nfrom langflow.schema.data import Data\n\n\nclass CalculatorComponent(Component):\n display_name = \"Calculator\"\n description = \"Perform basic arithmetic operations on a given expression.\"\n icon = \"calculator\"\n\n # Cache operators dictionary as a class variable\n OPERATORS: dict[type[ast.operator], Callable] = {\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\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 tool_mode=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"result\", type_=Data, method=\"evaluate_expression\"),\n ]\n\n def _eval_expr(self, node: ast.AST) -> float:\n \"\"\"Evaluate an AST node recursively.\"\"\"\n if isinstance(node, ast.Constant):\n if isinstance(node.value, int | float):\n return float(node.value)\n error_msg = f\"Unsupported constant type: {type(node.value).__name__}\"\n raise TypeError(error_msg)\n if isinstance(node, ast.Num): # For backwards compatibility\n if isinstance(node.n, int | float):\n return float(node.n)\n error_msg = f\"Unsupported number type: {type(node.n).__name__}\"\n raise TypeError(error_msg)\n\n if isinstance(node, ast.BinOp):\n op_type = type(node.op)\n if op_type not in self.OPERATORS:\n error_msg = f\"Unsupported binary operator: {op_type.__name__}\"\n raise TypeError(error_msg)\n\n left = self._eval_expr(node.left)\n right = self._eval_expr(node.right)\n return self.OPERATORS[op_type](left, right)\n\n error_msg = f\"Unsupported operation or expression type: {type(node).__name__}\"\n raise TypeError(error_msg)\n\n def evaluate_expression(self) -> Data:\n \"\"\"Evaluate the mathematical expression and return the result.\"\"\"\n try:\n tree = ast.parse(self.expression, mode=\"eval\")\n result = self._eval_expr(tree.body)\n\n formatted_result = f\"{float(result):.6f}\".rstrip(\"0\").rstrip(\".\")\n self.log(f\"Calculation result: {formatted_result}\")\n\n self.status = formatted_result\n return Data(data={\"result\": formatted_result})\n\n except ZeroDivisionError:\n error_message = \"Error: Division by zero\"\n self.status = error_message\n return Data(data={\"error\": error_message, \"input\": self.expression})\n\n except (SyntaxError, TypeError, KeyError, ValueError, AttributeError, OverflowError) as e:\n error_message = f\"Invalid expression: {e!s}\"\n self.status = error_message\n return Data(data={\"error\": error_message, \"input\": self.expression})\n\n def build(self):\n \"\"\"Return the main evaluation function.\"\"\"\n return self.evaluate_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, + "list_add_label": "Add More", + "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": "" + }, + "tools_metadata": { + "_input_type": "ToolsInput", + "advanced": false, + "display_name": "Actions", + "dynamic": false, + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", + "is_list": true, + "list_add_label": "Add More", + "name": "tools_metadata", + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "tools", + "value": [ + { + "args": { + "expression": { + "default": "", + "description": "The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').", + "title": "Expression", + "type": "string" + } + }, + "description": "Perform basic arithmetic operations on a given expression.", + "display_description": "Perform basic arithmetic operations on a given expression.", + "display_name": "evaluate_expression", + "name": "evaluate_expression", + "readonly": false, + "status": true, + "tags": [ + "evaluate_expression" + ] + } + ] + } + }, + "tool_mode": true + }, + "showNode": true, + "type": "CalculatorComponent" + }, + "dragging": false, + "id": "CalculatorComponent-JKeHR", + "measured": { + "height": 217, + "width": 320 + }, + "position": { + "x": 3427.6329448251768, + "y": 1066.3993526174263 + }, "selected": true, "type": "genericNode" } ], "viewport": { - "x": -750.9105189752929, - "y": 96.67627127061348, - "zoom": 0.44896152055995414 + "x": -1956.9334684808755, + "y": -270.19574649754327, + "zoom": 0.6669131453914963 } }, "description": "Create a travel planning chatbot that uses specialized agents to craft personalized trip itineraries.", "endpoint_name": null, - "id": "0148d85f-5339-4ba1-ae38-54b504c0223d", + "id": "95d851e7-4eb4-445b-a506-224570a44f37", "is_component": false, - "last_tested_version": "1.3.4", + "last_tested_version": "1.4.3", "name": "Travel Planning Agents", "tags": [ "agents",