diff --git a/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json index 96d708754..c00785bd2 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "AgentQL", - "id": "AgentQL-NY5vW", + "id": "AgentQL-u82BE", "name": "component_as_tool", "output_types": [ "Tool" @@ -15,19 +15,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-QRVSc", + "id": "Agent-PZpvb", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-AgentQL-NY5vW{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-NY5vWœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-QRVSc{œfieldNameœ:œtoolsœ,œidœ:œAgent-QRVScœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-AgentQL-u82BE{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-u82BEœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-PZpvb{œfieldNameœ:œtoolsœ,œidœ:œAgent-PZpvbœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "AgentQL-NY5vW", - "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-NY5vWœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-QRVSc", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-QRVScœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "AgentQL-u82BE", + "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-u82BEœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-PZpvb", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-PZpvbœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -35,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-tFY2s", + "id": "ChatInput-NRSAi", "name": "message", "output_types": [ "Message" @@ -43,19 +43,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-QRVSc", + "id": "Agent-PZpvb", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-tFY2s{œdataTypeœ:œChatInputœ,œidœ:œChatInput-tFY2sœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-QRVSc{œfieldNameœ:œinput_valueœ,œidœ:œAgent-QRVScœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-NRSAi{œdataTypeœ:œChatInputœ,œidœ:œChatInput-NRSAiœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-PZpvb{œfieldNameœ:œinput_valueœ,œidœ:œAgent-PZpvbœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-tFY2s", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-tFY2sœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-QRVSc", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-QRVScœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-NRSAi", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-NRSAiœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-PZpvb", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-PZpvbœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -63,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-QRVSc", + "id": "Agent-PZpvb", "name": "response", "output_types": [ "Message" @@ -71,7 +71,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-qeYkD", + "id": "ChatOutput-EKVmm", "inputTypes": [ "Data", "DataFrame", @@ -80,18 +80,46 @@ "type": "other" } }, - "id": "reactflow__edge-Agent-QRVSc{œdataTypeœ:œAgentœ,œidœ:œAgent-QRVScœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-qeYkD{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-qeYkDœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "xy-edge__Agent-PZpvb{œdataTypeœ:œAgentœ,œidœ:œAgent-PZpvbœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-EKVmm{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-EKVmmœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "Agent-QRVSc", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-QRVScœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-qeYkD", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-qeYkDœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "Agent-PZpvb", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-PZpvbœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-EKVmm", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-EKVmmœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "ChatOutput", + "id": "ChatOutput-EKVmm", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "message", + "id": "SaveToFile-yBiQe", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__ChatOutput-EKVmm{œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-EKVmmœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-SaveToFile-yBiQe{œfieldNameœ:œmessageœ,œidœ:œSaveToFile-yBiQeœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatOutput-EKVmm", + "sourceHandle": "{œdataTypeœ: œChatOutputœ, œidœ: œChatOutput-EKVmmœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "SaveToFile-yBiQe", + "targetHandle": "{œfieldNameœ: œmessageœ, œidœ: œSaveToFile-yBiQeœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "note-cvbuP", + "id": "note-2ZNem", "node": { "description": "### 💡 Add your OpenAI API key here", "display_name": "", @@ -103,21 +131,21 @@ "type": "note" }, "dragging": false, - "id": "note-cvbuP", + "id": "note-2ZNem", "measured": { "height": 324, "width": 324 }, "position": { - "x": 1170.377736042162, - "y": 143.70815416701694 + "x": 1173.6948654399118, + "y": 140.3910247692671 }, "selected": false, "type": "noteNode" }, { "data": { - "id": "note-lfFOf", + "id": "note-HtN4B", "node": { "description": "### 💡 Add your AgentQL API key here", "display_name": "", @@ -130,14 +158,14 @@ }, "dragging": false, "height": 346, - "id": "note-lfFOf", + "id": "note-HtN4B", "measured": { "height": 346, "width": 324 }, "position": { - "x": 741.8464477206785, - "y": 270.1565987952192 + "x": 754.0235442608289, + "y": 35.586746852834835 }, "selected": false, "type": "noteNode" @@ -146,7 +174,7 @@ "data": { "description": "Uses AgentQL API to extract structured data from a given URL.", "display_name": "AgentQL Query Data", - "id": "AgentQL-NY5vW", + "id": "AgentQL-u82BE", "node": { "base_classes": [ "Data" @@ -173,6 +201,7 @@ "frozen": false, "icon": "AgentQL", "legacy": false, + "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -214,7 +243,7 @@ "show": true, "title_case": false, "type": "str", - "value": "AGENTQL_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -538,21 +567,21 @@ "type": "AgentQL" }, "dragging": false, - "id": "AgentQL-NY5vW", + "id": "AgentQL-u82BE", "measured": { "height": 602, "width": 320 }, "position": { - "x": 746.6171255053692, - "y": 323.12336325015775 + "x": 754.0425636172196, + "y": 87.23877481296148 }, - "selected": true, + "selected": false, "type": "genericNode" }, { "data": { - "id": "ChatInput-tFY2s", + "id": "ChatInput-NRSAi", "node": { "base_classes": [ "Message" @@ -850,327 +879,21 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-tFY2s", + "id": "ChatInput-NRSAi", "measured": { "height": 66, "width": 192 }, "position": { - "x": 414.26981499855697, - "y": 618.0969310476024 + "x": 823.1132878482413, + "y": 728.3243379433505 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "ChatOutput-qeYkD", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "should_store_message", - "sender", - "sender_name", - "session_id", - "data_template", - "background_color", - "chat_icon", - "text_color", - "clean_data" - ], - "frozen": false, - "icon": "MessagesSquare", - "legacy": false, - "metadata": {}, - "minimized": true, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Message", - "method": "message_response", - "name": "message", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "background_color": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Background Color", - "dynamic": false, - "info": "The background color of the icon.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "background_color", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "chat_icon": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Icon", - "dynamic": false, - "info": "The icon of the message.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "chat_icon", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "clean_data": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Basic Clean Data", - "dynamic": false, - "info": "Whether to clean the data", - "list": false, - "list_add_label": "Add More", - "name": "clean_data", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "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 collections.abc import Generator\nfrom typing import Any\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.inputs.inputs import HandleInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\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 advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n info=\"Whether to clean the data\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n # Get source properties\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message):\n message = self.input_value\n # Update message properties\n message.text = text\n else:\n message = Message(text=text)\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n\n # Store message if needed\n if self.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def _safe_convert(self, data: Any) -> str:\n \"\"\"Safely convert input data to string.\"\"\"\n try:\n if isinstance(data, str):\n return data\n if isinstance(data, Message):\n return data.get_text()\n if isinstance(data, Data):\n if data.get_text() is None:\n msg = \"Empty Data object\"\n raise ValueError(msg)\n return data.get_text()\n if isinstance(data, DataFrame):\n if self.clean_data:\n # Remove empty rows\n data = data.dropna(how=\"all\")\n # Remove empty lines in each cell\n data = data.replace(r\"^\\s*$\", \"\", regex=True)\n # Replace multiple newlines with a single newline\n data = data.replace(r\"\\n+\", \"\\n\", regex=True)\n\n # Replace pipe characters to avoid markdown table issues\n processed_data = data.replace(r\"\\|\", r\"\\\\|\", regex=True)\n\n processed_data = processed_data.map(\n lambda x: str(x).replace(\"\\n\", \"
\") if isinstance(x, str) else x\n )\n\n return processed_data.to_markdown(index=False)\n return str(data)\n except (ValueError, TypeError, AttributeError) as e:\n msg = f\"Error converting data: {e!s}\"\n raise ValueError(msg) from e\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n return \"\\n\".join([self._safe_convert(item) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return self._safe_convert(self.input_value)\n" - }, - "data_template": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Data Template", - "dynamic": false, - "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "data_template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{text}" - }, - "input_value": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Text", - "dynamic": false, - "info": "Message to be passed as output.", - "input_types": [ - "Data", - "DataFrame", - "Message" - ], - "list": false, - "list_add_label": "Add More", - "name": "input_value", - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender Type", - "dynamic": false, - "info": "Type of sender.", - "name": "sender", - "options": [ - "Machine", - "User" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Machine" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Name of the sender.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "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": "AI" - }, - "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, - "list_add_label": "Add More", - "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": "" - }, - "should_store_message": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Store Messages", - "dynamic": false, - "info": "Store the message in the history.", - "list": false, - "list_add_label": "Add More", - "name": "should_store_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "text_color": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Text Color", - "dynamic": false, - "info": "The text color of the name", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "text_color", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - } - }, - "tool_mode": false - }, - "showNode": false, - "type": "ChatOutput" - }, - "dragging": false, - "id": "ChatOutput-qeYkD", - "measured": { - "height": 66, - "width": 192 - }, - "position": { - "x": 1564.8269684087277, - "y": 540 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Agent-QRVSc", + "id": "Agent-PZpvb", "node": { "base_classes": [ "Message" @@ -1213,6 +936,7 @@ "frozen": false, "icon": "bot", "legacy": false, + "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -1353,7 +1077,7 @@ "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1729,7 +1453,7 @@ "trace_as_input": true, "trace_as_metadata": true, "type": "str", - "value": "You are a helpful assistant that can use tools to answer questions and perform tasks." + "value": "You are a helpful content writer researching news and social posts for our company.\n\nCreate a new JSON file and insert the extracted data into that file.\n\nYou will use the AgentQL tool when getting content from URLs. Be sure to get the URL, author, content, and publish date. Here's how to write an AgentQL query:\n\nThe AgentQL query serves as the building block of your script. This guide shows you how AgentQL's query structure works and how to write a valid query.\n\n### Single term query\n\nA **single term query** enables you to retrieve a single element on the webpage. Here is an example of how you can write a single term query to retrieve a search box.\n\n```AgentQL\n{\n search_box\n}\n```\n\n### List term query\n\nA **list term query** enables you to retrieve a list of similar elements on the webpage. Here is an example of how you can write a list term query to retrieve a list of prices of apples.\n\n```AgentQL\n{\n apple_price[]\n}\n```\n\nYou can also specify the exact field you want to return in the list. Here is an example of how you can specify that you want the name and price from the list of products.\n\n```AgentQL\n{\n products[] {\n name\n price(integer)\n }\n}\n```\n\n### Combining single term queries and list term queries\n\nYou can query for both **single terms** and **list terms** by combining the preceding formats.\n\n```AgentQL\n{\n author\n date_of_birth\n book_titles[]\n}\n```\n\n### Giving context to queries\n\nThere two main ways you can provide additional context to your queries.\n\n#### Structural context\n\nYou can nest queries within parent containers to indicate that your target web element is in a particular section of the webpage.\n\n```AgentQL\n{\n footer {\n social_media_links[]\n }\n}\n```\n\n#### Semantic context\n\nYou can also provide a short description within parentheses to guide AgentQL in locating the right element(s).\n\n```AgentQL\n{\n footer {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n }\n}\n```\n\n### Syntax guidelines\n\nEnclose all AgentQL query terms within curly braces `{}`. The following query structure isn't valid because the term \"social_media_links\" is wrongly enclosed within parenthesis`()`.\n\n```AgentQL\n( # Should be {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n) # Should be }\n```\n\nYou can't include new lines in your semantic context. The following query structure isn't valid because the semantic context isn't contained within one line.\n\n```AgentQL\n{\n social_media_links(The icons that lead\n to Facebook, Snapchat, etc.)[]\n}\n```" }, "temperature": { "_input_type": "SliderInput", @@ -1846,7 +1570,7 @@ "type": "Agent" }, "dragging": false, - "id": "Agent-QRVSc", + "id": "Agent-PZpvb", "measured": { "height": 624, "width": 320 @@ -1860,9 +1584,9 @@ }, { "data": { - "id": "note-IV9Ka", + "id": "note-sjGvZ", "node": { - "description": "# News Aggregator\n\nThis flow extracts structured data from a URL.\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Click **Playground** and enter a question.\nThe **Agent** component populates the **Agent QL** component's **URL** and **Query** fields, and returns a structured response to your question.", + "description": "# News Aggregator\n\nThis flow extracts structured data from a URL and saves it into a JSON file.\n\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Click **Playground** and enter a question.\n\nThe **Agent** component populates the **AgentQL** component's **URL** and **Query** fields, and returns a structured response to your question. Then the extracted data is saved into a JSON file `news-aggregated.json`, which can be found in your current project directory.", "display_name": "", "documentation": "", "template": { @@ -1872,28 +1596,583 @@ "type": "note" }, "dragging": false, - "id": "note-IV9Ka", + "id": "note-sjGvZ", "measured": { - "height": 604, + "height": 717, "width": 325 }, "position": { - "x": 215.10951666579462, - "y": -25.20466668876412 + "x": 385.05237560524864, + "y": 75.15335682775009 + }, + "selected": false, + "type": "noteNode" + }, + { + "data": { + "id": "SaveToFile-yBiQe", + "node": { + "base_classes": [ + "Text" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Save DataFrames, Data, or Messages to various file formats.", + "display_name": "Save to File", + "documentation": "", + "edited": false, + "field_order": [ + "input_type", + "df", + "data", + "message", + "file_format", + "file_path" + ], + "frozen": false, + "icon": "save", + "legacy": false, + "lf_version": "1.2.0", + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Confirmation", + "method": "save_to_file", + "name": "confirmation", + "selected": "Text", + "tool_mode": true, + "types": [ + "Text" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "import json\nfrom collections.abc import AsyncIterator, Iterator\nfrom pathlib import Path\n\nimport pandas as pd\n\nfrom langflow.custom import Component\nfrom langflow.io import (\n DataFrameInput,\n DataInput,\n DropdownInput,\n MessageInput,\n Output,\n StrInput,\n)\nfrom langflow.schema import Data, DataFrame, Message\n\n\nclass SaveToFileComponent(Component):\n display_name = \"Save to File\"\n description = \"Save DataFrames, Data, or Messages to various file formats.\"\n icon = \"save\"\n name = \"SaveToFile\"\n\n # File format options for different types\n DATA_FORMAT_CHOICES = [\"csv\", \"excel\", \"json\", \"markdown\"]\n MESSAGE_FORMAT_CHOICES = [\"txt\", \"json\", \"markdown\"]\n\n inputs = [\n DropdownInput(\n name=\"input_type\",\n display_name=\"Input Type\",\n options=[\"DataFrame\", \"Data\", \"Message\"],\n info=\"Select the type of input to save.\",\n value=\"DataFrame\",\n real_time_refresh=True,\n ),\n DataFrameInput(\n name=\"df\",\n display_name=\"DataFrame\",\n info=\"The DataFrame to save.\",\n dynamic=True,\n show=True,\n ),\n DataInput(\n name=\"data\",\n display_name=\"Data\",\n info=\"The Data object to save.\",\n dynamic=True,\n show=False,\n ),\n MessageInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The Message to save.\",\n dynamic=True,\n show=False,\n ),\n DropdownInput(\n name=\"file_format\",\n display_name=\"File Format\",\n options=DATA_FORMAT_CHOICES,\n info=\"Select the file format to save the input.\",\n real_time_refresh=True,\n ),\n StrInput(\n name=\"file_path\",\n display_name=\"File Path (including filename)\",\n info=\"The full file path (including filename and extension).\",\n value=\"./output\",\n ),\n ]\n\n outputs = [\n Output(\n name=\"confirmation\",\n display_name=\"Confirmation\",\n method=\"save_to_file\",\n info=\"Confirmation message after saving the file.\",\n ),\n ]\n\n def update_build_config(self, build_config, field_value, field_name=None):\n # Hide/show dynamic fields based on the selected input type\n if field_name == \"input_type\":\n build_config[\"df\"][\"show\"] = field_value == \"DataFrame\"\n build_config[\"data\"][\"show\"] = field_value == \"Data\"\n build_config[\"message\"][\"show\"] = field_value == \"Message\"\n\n if field_value in {\"DataFrame\", \"Data\"}:\n build_config[\"file_format\"][\"options\"] = self.DATA_FORMAT_CHOICES\n elif field_value == \"Message\":\n build_config[\"file_format\"][\"options\"] = self.MESSAGE_FORMAT_CHOICES\n\n return build_config\n\n def save_to_file(self) -> str:\n input_type = self.input_type\n file_format = self.file_format\n file_path = Path(self.file_path).expanduser()\n\n # Ensure the directory exists\n if not file_path.parent.exists():\n file_path.parent.mkdir(parents=True, exist_ok=True)\n\n if input_type == \"DataFrame\":\n dataframe = self.df\n return self._save_dataframe(dataframe, file_path, file_format)\n if input_type == \"Data\":\n data = self.data\n return self._save_data(data, file_path, file_format)\n if input_type == \"Message\":\n message = self.message\n return self._save_message(message, file_path, file_format)\n\n error_msg = f\"Unsupported input type: {input_type}\"\n raise ValueError(error_msg)\n\n def _save_dataframe(self, dataframe: DataFrame, path: Path, fmt: str) -> str:\n if fmt == \"csv\":\n dataframe.to_csv(path, index=False)\n elif fmt == \"excel\":\n dataframe.to_excel(path, index=False, engine=\"openpyxl\")\n elif fmt == \"json\":\n dataframe.to_json(path, orient=\"records\", indent=2)\n elif fmt == \"markdown\":\n path.write_text(dataframe.to_markdown(index=False), encoding=\"utf-8\")\n else:\n error_msg = f\"Unsupported DataFrame format: {fmt}\"\n raise ValueError(error_msg)\n\n return f\"DataFrame saved successfully as '{path}'\"\n\n def _save_data(self, data: Data, path: Path, fmt: str) -> str:\n if fmt == \"csv\":\n pd.DataFrame(data.data).to_csv(path, index=False)\n elif fmt == \"excel\":\n pd.DataFrame(data.data).to_excel(path, index=False, engine=\"openpyxl\")\n elif fmt == \"json\":\n path.write_text(json.dumps(data.data, indent=2), encoding=\"utf-8\")\n elif fmt == \"markdown\":\n path.write_text(pd.DataFrame(data.data).to_markdown(index=False), encoding=\"utf-8\")\n else:\n error_msg = f\"Unsupported Data format: {fmt}\"\n raise ValueError(error_msg)\n\n return f\"Data saved successfully as '{path}'\"\n\n def _save_message(self, message: Message, path: Path, fmt: str) -> str:\n if message.text is None:\n content = \"\"\n elif isinstance(message.text, AsyncIterator):\n # AsyncIterator needs to be handled differently\n error_msg = \"AsyncIterator not supported\"\n raise ValueError(error_msg)\n elif isinstance(message.text, Iterator):\n # Convert iterator to string\n content = \" \".join(str(item) for item in message.text)\n else:\n content = str(message.text)\n\n if fmt == \"txt\":\n path.write_text(content, encoding=\"utf-8\")\n elif fmt == \"json\":\n path.write_text(json.dumps({\"message\": content}, indent=2), encoding=\"utf-8\")\n elif fmt == \"markdown\":\n path.write_text(f\"**Message:**\\n\\n{content}\", encoding=\"utf-8\")\n else:\n error_msg = f\"Unsupported Message format: {fmt}\"\n raise ValueError(error_msg)\n\n return f\"Message saved successfully as '{path}'\"\n" + }, + "data": { + "_input_type": "DataInput", + "advanced": false, + "display_name": "Data", + "dynamic": true, + "info": "The Data object to save.", + "input_types": [ + "Data" + ], + "list": false, + "list_add_label": "Add More", + "name": "data", + "placeholder": "", + "required": false, + "show": false, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "df": { + "_input_type": "DataFrameInput", + "advanced": false, + "display_name": "DataFrame", + "dynamic": true, + "info": "The DataFrame to save.", + "input_types": [ + "DataFrame" + ], + "list": false, + "list_add_label": "Add More", + "name": "df", + "placeholder": "", + "required": false, + "show": false, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "file_format": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "File Format", + "dynamic": false, + "info": "Select the file format to save the input.", + "name": "file_format", + "options": [ + "csv", + "excel", + "json", + "markdown" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "json" + }, + "file_path": { + "_input_type": "StrInput", + "advanced": false, + "display_name": "File Path (including filename)", + "dynamic": false, + "info": "The full file path (including filename and extension).", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "file_path", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "./news-aggregated.json" + }, + "input_type": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Input Type", + "dynamic": false, + "info": "Select the type of input to save.", + "name": "input_type", + "options": [ + "DataFrame", + "Data", + "Message" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "Message" + }, + "message": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Message", + "dynamic": true, + "info": "The Message to save.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + } + }, + "tool_mode": false + }, + "showNode": true, + "type": "SaveToFile" + }, + "dragging": false, + "id": "SaveToFile-yBiQe", + "measured": { + "height": 497, + "width": 320 + }, + "position": { + "x": 1792.6734722792191, + "y": 270.7843661133249 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "ChatOutput-EKVmm", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Display a chat message in the Playground.", + "display_name": "Chat Output", + "documentation": "", + "edited": false, + "field_order": [ + "input_value", + "should_store_message", + "sender", + "sender_name", + "session_id", + "data_template", + "background_color", + "chat_icon", + "text_color", + "clean_data" + ], + "frozen": false, + "icon": "MessagesSquare", + "legacy": false, + "lf_version": "1.2.0", + "metadata": {}, + "minimized": true, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Message", + "method": "message_response", + "name": "message", + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "background_color": { + "_input_type": "MessageTextInput", + "advanced": true, + "display_name": "Background Color", + "dynamic": false, + "info": "The background color of the icon.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "background_color", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "chat_icon": { + "_input_type": "MessageTextInput", + "advanced": true, + "display_name": "Icon", + "dynamic": false, + "info": "The icon of the message.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "chat_icon", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "clean_data": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Basic Clean Data", + "dynamic": false, + "info": "Whether to clean the data", + "list": false, + "list_add_label": "Add More", + "name": "clean_data", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "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 collections.abc import Generator\nfrom typing import Any\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.inputs.inputs import HandleInput\nfrom langflow.io import DropdownInput, MessageTextInput, Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.message import Message\nfrom langflow.schema.properties import Source\nfrom langflow.utils.constants import (\n MESSAGE_SENDER_AI,\n MESSAGE_SENDER_NAME_AI,\n MESSAGE_SENDER_USER,\n)\n\n\nclass ChatOutput(ChatComponent):\n display_name = \"Chat Output\"\n description = \"Display a chat message in the Playground.\"\n icon = \"MessagesSquare\"\n name = \"ChatOutput\"\n minimized = True\n\n inputs = [\n HandleInput(\n name=\"input_value\",\n display_name=\"Text\",\n info=\"Message to be passed as output.\",\n input_types=[\"Data\", \"DataFrame\", \"Message\"],\n required=True,\n ),\n BoolInput(\n name=\"should_store_message\",\n display_name=\"Store Messages\",\n info=\"Store the message in the history.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"sender\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER],\n value=MESSAGE_SENDER_AI,\n advanced=True,\n info=\"Type of sender.\",\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Name of the sender.\",\n value=MESSAGE_SENDER_NAME_AI,\n advanced=True,\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 advanced=True,\n ),\n MessageTextInput(\n name=\"data_template\",\n display_name=\"Data Template\",\n value=\"{text}\",\n advanced=True,\n info=\"Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.\",\n ),\n MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n info=\"Whether to clean the data\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"Message\",\n name=\"message\",\n method=\"message_response\",\n ),\n ]\n\n def _build_source(self, id_: str | None, display_name: str | None, source: str | None) -> Source:\n source_dict = {}\n if id_:\n source_dict[\"id\"] = id_\n if display_name:\n source_dict[\"display_name\"] = display_name\n if source:\n # Handle case where source is a ChatOpenAI object\n if hasattr(source, \"model_name\"):\n source_dict[\"source\"] = source.model_name\n elif hasattr(source, \"model\"):\n source_dict[\"source\"] = str(source.model)\n else:\n source_dict[\"source\"] = str(source)\n return Source(**source_dict)\n\n async def message_response(self) -> Message:\n # First convert the input to string if needed\n text = self.convert_to_string()\n # Get source properties\n source, icon, display_name, source_id = self.get_properties_from_source_component()\n background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message):\n message = self.input_value\n # Update message properties\n message.text = text\n else:\n message = Message(text=text)\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n\n # Store message if needed\n if self.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _validate_input(self) -> None:\n \"\"\"Validate the input data and raise ValueError if invalid.\"\"\"\n if self.input_value is None:\n msg = \"Input data cannot be None\"\n raise ValueError(msg)\n if isinstance(self.input_value, list) and not all(\n isinstance(item, Message | Data | DataFrame | str) for item in self.input_value\n ):\n invalid_types = [\n type(item).__name__\n for item in self.input_value\n if not isinstance(item, Message | Data | DataFrame | str)\n ]\n msg = f\"Expected Data or DataFrame or Message or str, got {invalid_types}\"\n raise TypeError(msg)\n if not isinstance(\n self.input_value,\n Message | Data | DataFrame | str | list | Generator | type(None),\n ):\n type_name = type(self.input_value).__name__\n msg = f\"Expected Data or DataFrame or Message or str, Generator or None, got {type_name}\"\n raise TypeError(msg)\n\n def _safe_convert(self, data: Any) -> str:\n \"\"\"Safely convert input data to string.\"\"\"\n try:\n if isinstance(data, str):\n return data\n if isinstance(data, Message):\n return data.get_text()\n if isinstance(data, Data):\n if data.get_text() is None:\n msg = \"Empty Data object\"\n raise ValueError(msg)\n return data.get_text()\n if isinstance(data, DataFrame):\n if self.clean_data:\n # Remove empty rows\n data = data.dropna(how=\"all\")\n # Remove empty lines in each cell\n data = data.replace(r\"^\\s*$\", \"\", regex=True)\n # Replace multiple newlines with a single newline\n data = data.replace(r\"\\n+\", \"\\n\", regex=True)\n\n # Replace pipe characters to avoid markdown table issues\n processed_data = data.replace(r\"\\|\", r\"\\\\|\", regex=True)\n\n processed_data = processed_data.map(\n lambda x: str(x).replace(\"\\n\", \"
\") if isinstance(x, str) else x\n )\n\n return processed_data.to_markdown(index=False)\n return str(data)\n except (ValueError, TypeError, AttributeError) as e:\n msg = f\"Error converting data: {e!s}\"\n raise ValueError(msg) from e\n\n def convert_to_string(self) -> str | Generator[Any, None, None]:\n \"\"\"Convert input data to string with proper error handling.\"\"\"\n self._validate_input()\n if isinstance(self.input_value, list):\n return \"\\n\".join([self._safe_convert(item) for item in self.input_value])\n if isinstance(self.input_value, Generator):\n return self.input_value\n return self._safe_convert(self.input_value)\n" + }, + "data_template": { + "_input_type": "MessageTextInput", + "advanced": true, + "display_name": "Data Template", + "dynamic": false, + "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "data_template", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "{text}" + }, + "input_value": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Text", + "dynamic": false, + "info": "Message to be passed as output.", + "input_types": [ + "Data", + "DataFrame", + "Message" + ], + "list": false, + "list_add_label": "Add More", + "name": "input_value", + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "sender": { + "_input_type": "DropdownInput", + "advanced": true, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Sender Type", + "dynamic": false, + "info": "Type of sender.", + "name": "sender", + "options": [ + "Machine", + "User" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "Machine" + }, + "sender_name": { + "_input_type": "MessageTextInput", + "advanced": true, + "display_name": "Sender Name", + "dynamic": false, + "info": "Name of the sender.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "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": "AI" + }, + "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, + "list_add_label": "Add More", + "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": "" + }, + "should_store_message": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Store Messages", + "dynamic": false, + "info": "Store the message in the history.", + "list": false, + "list_add_label": "Add More", + "name": "should_store_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "text_color": { + "_input_type": "MessageTextInput", + "advanced": true, + "display_name": "Text Color", + "dynamic": false, + "info": "The text color of the name", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "text_color", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + } + }, + "tool_mode": false + }, + "showNode": false, + "type": "ChatOutput" + }, + "dragging": false, + "id": "ChatOutput-EKVmm", + "measured": { + "height": 66, + "width": 192 + }, + "position": { + "x": 1550.6058181803635, + "y": 480.66205042564377 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "note-CWRHQ", + "node": { + "description": "# Example Input\n\nYou can start off with this example on **Playground**:\n\n\"\"\"\n\nWrite a JSON file of all job postings from the following career pages:\nhttps://www.ycombinator.com/jobs\nhttps://www.indeed.com/jobs?q=Full+Time&l=Palo+Alto,+CA&from=mobRdr&utm_source=/m/&utm_medium=redir&utm_campaign=dt&vjk=87bf09250c117a5b\n\nInclude columns for: Posted Date (in MM-DD-YYYY format) | Job Title | Company | Location | Job URL | Employment Type (Full-time, Part-time, Contract, etc.) | Remote Eligibility (Yes/No) | Suggested Outreach\n\nIn the Suggested Outreach column: Suggest a brief message our recruiters could send to a potential candidate.\n\nAt the end, summarize the most in-demand skills and trends based on the job descriptions in a paragraph for our internal hiring strategy report.\n\n\"\"\"", + "display_name": "", + "documentation": "", + "template": { + "backgroundColor": "rose" + } + }, + "type": "note" + }, + "dragging": false, + "id": "note-CWRHQ", + "measured": { + "height": 772, + "width": 325 + }, + "position": { + "x": 10.416897440247894, + "y": 74.31274172013815 }, "selected": false, "type": "noteNode" } ], "viewport": { - "x": -117.84864069491266, - "y": 81.66532371797462, - "zoom": 0.8538293672913081 + "x": 58.56326820207494, + "y": 87.91060080304197, + "zoom": 0.6029309563132144 } }, "description": "Extracts data and information from webpages.", "endpoint_name": null, - "id": "668ff2ee-3592-47f6-a144-a3eea2150e6a", + "icon": "Newspaper", + "id": "30cdfac5-8aca-48f1-8a90-72e2573473c4", "is_component": false, "last_tested_version": "1.2.0", "name": "News Aggregator", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json index 6939f5783..a47157ba5 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "AgentQL", - "id": "AgentQL-SX5lE", + "id": "AgentQL-BPZh4", "name": "component_as_tool", "output_types": [ "Tool" @@ -15,75 +15,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-6kg5B", + "id": "Agent-Bh2Yb", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-AgentQL-SX5lE{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-SX5lEœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-6kg5B{œfieldNameœ:œtoolsœ,œidœ:œAgent-6kg5Bœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-AgentQL-BPZh4{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-BPZh4œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-Bh2Yb{œfieldNameœ:œtoolsœ,œidœ:œAgent-Bh2Ybœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "AgentQL-SX5lE", - "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-SX5lEœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-6kg5B", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-6kg5Bœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "TavilySearchComponent", - "id": "TavilySearchComponent-rYJ93", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-6kg5B", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-TavilySearchComponent-rYJ93{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-rYJ93œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-6kg5B{œfieldNameœ:œtoolsœ,œidœ:œAgent-6kg5Bœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "TavilySearchComponent-rYJ93", - "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-rYJ93œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-6kg5B", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-6kg5Bœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-RjE2C", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-6kg5B", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-RjE2C{œdataTypeœ:œChatInputœ,œidœ:œChatInput-RjE2Cœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-6kg5B{œfieldNameœ:œinput_valueœ,œidœ:œAgent-6kg5Bœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-RjE2C", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-RjE2Cœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-6kg5B", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-6kg5Bœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "AgentQL-BPZh4", + "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-BPZh4œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-Bh2Yb", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-Bh2Ybœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -91,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-6kg5B", + "id": "Agent-Bh2Yb", "name": "response", "output_types": [ "Message" @@ -99,27 +43,83 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-x7zHw", + "id": "ChatOutput-E2Kiz", "inputTypes": [ "Data", "DataFrame", "Message" ], + "type": "str" + } + }, + "id": "reactflow__edge-Agent-Bh2Yb{œdataTypeœ:œAgentœ,œidœ:œAgent-Bh2Ybœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-E2Kiz{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-E2Kizœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Agent-Bh2Yb", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-Bh2Ybœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-E2Kiz", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-E2Kizœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "TavilySearchComponent", + "id": "TavilySearchComponent-EKeDo", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-Bh2Yb", + "inputTypes": [ + "Tool" + ], "type": "other" } }, - "id": "reactflow__edge-Agent-6kg5B{œdataTypeœ:œAgentœ,œidœ:œAgent-6kg5Bœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-x7zHw{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-x7zHwœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-TavilySearchComponent-EKeDo{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-EKeDoœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-Bh2Yb{œfieldNameœ:œtoolsœ,œidœ:œAgent-Bh2Ybœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "Agent-6kg5B", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-6kg5Bœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-x7zHw", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-x7zHwœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "TavilySearchComponent-EKeDo", + "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-EKeDoœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-Bh2Yb", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-Bh2Ybœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-5OxIN", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-Bh2Yb", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-5OxIN{œdataTypeœ:œChatInputœ,œidœ:œChatInput-5OxINœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-Bh2Yb{œfieldNameœ:œinput_valueœ,œidœ:œAgent-Bh2Ybœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-5OxIN", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-5OxINœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-Bh2Yb", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-Bh2Ybœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-RjE2C", + "id": "ChatInput-5OxIN", "node": { "base_classes": [ "Message" @@ -272,7 +272,6 @@ "placeholder": "", "required": false, "show": true, - "temp_file": true, "title_case": false, "trace_as_metadata": true, "type": "file", @@ -417,26 +416,27 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-RjE2C", + "id": "ChatInput-5OxIN", "measured": { "height": 66, "width": 192 }, "position": { - "x": 29.709503239241485, - "y": 315.10028395094986 + "x": 62.33311391612975, + "y": 677.8206598034913 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "ChatOutput-x7zHw", + "id": "ChatOutput-E2Kiz", "node": { "base_classes": [ "Message" ], "beta": false, + "category": "outputs", "conditional_paths": [], "custom_fields": {}, "description": "Display a chat message in the Playground.", @@ -452,12 +452,13 @@ "data_template", "background_color", "chat_icon", - "text_color", - "clean_data" + "text_color" ], "frozen": false, "icon": "MessagesSquare", + "key": "ChatOutput", "legacy": false, + "lf_version": "1.2.0", "metadata": {}, "minimized": true, "output_types": [], @@ -477,6 +478,7 @@ } ], "pinned": false, + "score": 0.00012027401062119145, "template": { "_type": "Component", "background_color": { @@ -585,7 +587,7 @@ "value": "{text}" }, "input_value": { - "_input_type": "HandleInput", + "_input_type": "MessageInput", "advanced": false, "display_name": "Text", "dynamic": false, @@ -597,13 +599,16 @@ ], "list": false, "list_add_label": "Add More", + "load_from_db": false, "name": "input_value", "placeholder": "", "required": true, "show": true, "title_case": false, + "tool_mode": false, + "trace_as_input": true, "trace_as_metadata": true, - "type": "other", + "type": "str", "value": "" }, "sender": { @@ -723,7 +728,7 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-x7zHw", + "id": "ChatOutput-E2Kiz", "measured": { "height": 66, "width": 192 @@ -737,7 +742,7 @@ }, { "data": { - "id": "TavilySearchComponent-rYJ93", + "id": "TavilySearchComponent-EKeDo", "node": { "base_classes": [ "Data", @@ -804,7 +809,7 @@ "show": true, "title_case": false, "type": "str", - "value": "TAVILY_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -983,37 +988,43 @@ "table_schema": { "columns": [ { + "default": "None", "description": "Specify the name of the tool.", "disable_edit": false, "display_name": "Tool Name", "edit_mode": "inline", "filterable": false, "formatter": "text", + "hidden": false, "name": "name", "sortable": false, - "type": "text" + "type": "str" }, { + "default": "None", "description": "Describe the purpose of the tool.", "disable_edit": false, "display_name": "Tool Description", "edit_mode": "popover", "filterable": false, "formatter": "text", + "hidden": false, "name": "description", "sortable": false, - "type": "text" + "type": "str" }, { + "default": "None", "description": "The default identifiers for the tools and cannot be changed.", "disable_edit": true, "display_name": "Tool Identifiers", "edit_mode": "inline", "filterable": false, "formatter": "text", + "hidden": true, "name": "tags", "sortable": false, - "type": "text" + "type": "str" } ] }, @@ -1070,23 +1081,23 @@ "type": "TavilySearchComponent" }, "dragging": false, - "id": "TavilySearchComponent-rYJ93", + "id": "TavilySearchComponent-EKeDo", "measured": { "height": 437, "width": 320 }, "position": { - "x": 345.9762510966062, - "y": 500.79656821057074 + "x": 39.12408438765479, + "y": 180.97658284912208 }, - "selected": true, + "selected": false, "type": "genericNode" }, { "data": { "description": "Uses AgentQL API to extract structured data from a given URL.", "display_name": "AgentQL Query Data", - "id": "AgentQL-SX5lE", + "id": "AgentQL-BPZh4", "node": { "base_classes": [ "Data" @@ -1113,6 +1124,7 @@ "frozen": false, "icon": "AgentQL", "legacy": false, + "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -1154,7 +1166,7 @@ "show": true, "title_case": false, "type": "str", - "value": "AGENTQL_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1478,21 +1490,21 @@ "type": "AgentQL" }, "dragging": false, - "id": "AgentQL-SX5lE", + "id": "AgentQL-BPZh4", "measured": { "height": 602, "width": 320 }, "position": { - "x": 331.42030247682777, - "y": -359.7956260200852 + "x": 419.9837597695889, + "y": 103.27516079272866 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "Agent-6kg5B", + "id": "Agent-Bh2Yb", "node": { "base_classes": [ "Message" @@ -1535,6 +1547,7 @@ "frozen": false, "icon": "bot", "legacy": false, + "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -1619,35 +1632,7 @@ "SambaNova", "Custom" ], - "options_metadata": [ - { - "icon": "Amazon" - }, - { - "icon": "Anthropic" - }, - { - "icon": "Azure" - }, - { - "icon": "GoogleGenerativeAI" - }, - { - "icon": "Groq" - }, - { - "icon": "NVIDIA" - }, - { - "icon": "OpenAI" - }, - { - "icon": "SambaNova" - }, - { - "icon": "brain" - } - ], + "options_metadata": [], "placeholder": "", "real_time_refresh": true, "required": false, @@ -1675,7 +1660,7 @@ "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -2168,21 +2153,21 @@ "type": "Agent" }, "dragging": false, - "id": "Agent-6kg5B", + "id": "Agent-Bh2Yb", "measured": { "height": 624, "width": 320 }, "position": { - "x": 783.7651594706487, - "y": -83.86659665829183 + "x": 806.8155719016273, + "y": 96.34571871117743 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "note-l316C", + "id": "note-IpT5f", "node": { "description": "### 💡 Add your OpenAI API key here", "display_name": "", @@ -2194,21 +2179,21 @@ "type": "note" }, "dragging": false, - "id": "note-l316C", + "id": "note-IpT5f", "measured": { "height": 324, "width": 324 }, "position": { - "x": 775.1028775592921, - "y": -131.5725508478389 + "x": 798.1532899902708, + "y": 48.63976452163034 }, "selected": false, "type": "noteNode" }, { "data": { - "id": "note-9uZJm", + "id": "note-vZk9B", "node": { "description": "### 💡 Add your AgentQL API key here", "display_name": "", @@ -2221,23 +2206,23 @@ }, "dragging": false, "height": 346, - "id": "note-9uZJm", + "id": "note-vZk9B", "measured": { "height": 346, "width": 324 }, "position": { - "x": 338.27967602049426, - "y": -413.92602911511665 + "x": 416.2302078823729, + "y": 51.23403819068896 }, "selected": false, "type": "noteNode" }, { "data": { - "id": "note-X4Slm", + "id": "note-ljICz", "node": { - "description": "# Price Deal Finder \n\nThis flow extracts structured data from a URL.\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n* **[TavilyAI Search API Key](https://tavily.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Add your [TavilyAI Search API Key](https://tavily.com/) to the **Tavily AI Search** component.\n4. Click **Playground** and enter a product in chat. For example, search \"Nintendo Switch - OLed Model - w/ White Joy-Con\")\n* The **Agent** component populates the **Tavily AI Search** component's **Search Query** field, and the **Agent QL** component's **URL** and **Query** fields. \n\n* The **Agent** returns a structured response to your searcn in the chat.", + "description": "# Price Deal Finder \n\nThis flow searches and compares prices of a product on the web.\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n* **[TavilyAI Search API Key](https://tavily.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Add your [TavilyAI Search API Key](https://tavily.com/) to the **Tavily AI Search** component.\n4. Click **Playground** and enter a product in chat. For example, search \"Nintendo Switch - OLed Model - w/ White Joy-Con\")\n* The **Agent** component populates the **Tavily AI Search** component's **Search Query** field, and the **Agent QL** component's **URL** and **Query** fields. \n\n* The **Agent** returns a structured response to your searcn in the chat.", "display_name": "", "documentation": "", "template": {} @@ -2246,7 +2231,7 @@ }, "dragging": false, "height": 674, - "id": "note-X4Slm", + "id": "note-ljICz", "measured": { "height": 674, "width": 467 @@ -2262,7 +2247,7 @@ }, { "data": { - "id": "note-s2MdP", + "id": "note-izBjK", "node": { "description": "### 💡 Add your Tavily AI Search key here", "display_name": "", @@ -2275,14 +2260,14 @@ }, "dragging": false, "height": 324, - "id": "note-s2MdP", + "id": "note-izBjK", "measured": { "height": 324, "width": 344 }, "position": { - "x": 343.1587328324782, - "y": 449.2345675374778 + "x": 25.144734571805117, + "y": 126.6122587862217 }, "resizing": false, "selected": false, @@ -2291,17 +2276,18 @@ } ], "viewport": { - "x": 424.9980860019988, - "y": 301.1687784963252, - "zoom": 0.6254645347553064 + "x": 347.94750627231167, + "y": 72.60494065370943, + "zoom": 0.5984998010566305 } }, "description": "Searches and compares product prices across multiple e-commerce platforms. ", "endpoint_name": null, - "id": "44912ccb-acc0-4963-bdf6-1274bc455b63", + "icon": "DollarSign", + "id": "325260a0-6ecf-4e55-b96f-0a56536ddc66", "is_component": false, "last_tested_version": "1.2.0", - "name": "Price Deal Finder", + "name": "Price Deal Finder ", "tags": [ "web-scraping", "agents"