{
  "data": {
    "edges": [
      {
        "animated": false,
        "className": "",
        "data": {
          "sourceHandle": {
            "dataType": "ChatInput",
            "id": "ChatInput-u8rae",
            "name": "message",
            "output_types": [
              "Message"
            ]
          },
          "targetHandle": {
            "fieldName": "USER_INPUT",
            "id": "Prompt-7Jzfo",
            "inputTypes": [
              "Message",
              "Text"
            ],
            "type": "str"
          }
        },
        "id": "reactflow__edge-ChatInput-u8rae{œdataTypeœ:œChatInputœ,œidœ:œChatInput-u8raeœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-7Jzfo{œfieldNameœ:œUSER_INPUTœ,œidœ:œPrompt-7Jzfoœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
        "selected": false,
        "source": "ChatInput-u8rae",
        "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-u8raeœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}",
        "target": "Prompt-7Jzfo",
        "targetHandle": "{œfieldNameœ: œUSER_INPUTœ, œidœ: œPrompt-7Jzfoœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
      },
      {
        "animated": false,
        "className": "",
        "data": {
          "sourceHandle": {
            "dataType": "Memory",
            "id": "Memory-U33nr",
            "name": "messages_text",
            "output_types": [
              "Message"
            ]
          },
          "targetHandle": {
            "fieldName": "CHAT_HISTORY",
            "id": "Prompt-7Jzfo",
            "inputTypes": [
              "Message",
              "Text"
            ],
            "type": "str"
          }
        },
        "id": "reactflow__edge-Memory-U33nr{œdataTypeœ:œMemoryœ,œidœ:œMemory-U33nrœ,œnameœ:œmessages_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-7Jzfo{œfieldNameœ:œCHAT_HISTORYœ,œidœ:œPrompt-7Jzfoœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
        "selected": false,
        "source": "Memory-U33nr",
        "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-U33nrœ, œnameœ: œmessages_textœ, œoutput_typesœ: [œMessageœ]}",
        "target": "Prompt-7Jzfo",
        "targetHandle": "{œfieldNameœ: œCHAT_HISTORYœ, œidœ: œPrompt-7Jzfoœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
      },
      {
        "animated": false,
        "className": "",
        "data": {
          "sourceHandle": {
            "dataType": "URL",
            "id": "URL-LiTXv",
            "name": "raw_results",
            "output_types": [
              "Message"
            ]
          },
          "targetHandle": {
            "fieldName": "EXAMPLE_COMPONENTS",
            "id": "Prompt-7Jzfo",
            "inputTypes": [
              "Message",
              "Text"
            ],
            "type": "str"
          }
        },
        "id": "reactflow__edge-URL-LiTXv{œdataTypeœ:œURLœ,œidœ:œURL-LiTXvœ,œnameœ:œraw_resultsœ,œoutput_typesœ:[œMessageœ]}-Prompt-7Jzfo{œfieldNameœ:œEXAMPLE_COMPONENTSœ,œidœ:œPrompt-7Jzfoœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
        "selected": false,
        "source": "URL-LiTXv",
        "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-LiTXvœ, œnameœ: œraw_resultsœ, œoutput_typesœ: [œMessageœ]}",
        "target": "Prompt-7Jzfo",
        "targetHandle": "{œfieldNameœ: œEXAMPLE_COMPONENTSœ, œidœ: œPrompt-7Jzfoœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
      },
      {
        "animated": false,
        "className": "",
        "data": {
          "sourceHandle": {
            "dataType": "URL",
            "id": "URL-E6QCv",
            "name": "raw_results",
            "output_types": [
              "Message"
            ]
          },
          "targetHandle": {
            "fieldName": "CUSTOM_COMPONENT_CODE",
            "id": "Prompt-7Jzfo",
            "inputTypes": [
              "Message",
              "Text"
            ],
            "type": "str"
          }
        },
        "id": "reactflow__edge-URL-E6QCv{œdataTypeœ:œURLœ,œidœ:œURL-E6QCvœ,œnameœ:œraw_resultsœ,œoutput_typesœ:[œMessageœ]}-Prompt-7Jzfo{œfieldNameœ:œCUSTOM_COMPONENT_CODEœ,œidœ:œPrompt-7Jzfoœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
        "selected": false,
        "source": "URL-E6QCv",
        "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-E6QCvœ, œnameœ: œraw_resultsœ, œoutput_typesœ: [œMessageœ]}",
        "target": "Prompt-7Jzfo",
        "targetHandle": "{œfieldNameœ: œCUSTOM_COMPONENT_CODEœ, œidœ: œPrompt-7Jzfoœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
      },
      {
        "animated": false,
        "className": "",
        "data": {
          "sourceHandle": {
            "dataType": "Prompt",
            "id": "Prompt-7Jzfo",
            "name": "prompt",
            "output_types": [
              "Message"
            ]
          },
          "targetHandle": {
            "fieldName": "input_value",
            "id": "LanguageModelComponent-muTzI",
            "inputTypes": [
              "Message"
            ],
            "type": "str"
          }
        },
        "id": "reactflow__edge-Prompt-7Jzfo{œdataTypeœ:œPromptœ,œidœ:œPrompt-7Jzfoœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-muTzI{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-muTzIœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}",
        "selected": false,
        "source": "Prompt-7Jzfo",
        "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-7Jzfoœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}",
        "target": "LanguageModelComponent-muTzI",
        "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-muTzIœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}"
      },
      {
        "animated": false,
        "className": "",
        "data": {
          "sourceHandle": {
            "dataType": "LanguageModelComponent",
            "id": "LanguageModelComponent-muTzI",
            "name": "text_output",
            "output_types": [
              "Message"
            ]
          },
          "targetHandle": {
            "fieldName": "input_value",
            "id": "ChatOutput-qF9Bn",
            "inputTypes": [
              "Data",
              "DataFrame",
              "Message"
            ],
            "type": "other"
          }
        },
        "id": "reactflow__edge-LanguageModelComponent-muTzI{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-muTzIœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-qF9Bn{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-qF9Bnœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}",
        "selected": false,
        "source": "LanguageModelComponent-muTzI",
        "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-muTzIœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}",
        "target": "ChatOutput-qF9Bn",
        "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-qF9Bnœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}"
      },
      {
        "animated": false,
        "className": "",
        "data": {
          "sourceHandle": {
            "dataType": "URL",
            "id": "URL-Gj8oh",
            "name": "raw_results",
            "output_types": [
              "Message"
            ]
          },
          "targetHandle": {
            "fieldName": "BASE_COMPONENT_CODE",
            "id": "Prompt-7Jzfo",
            "inputTypes": [
              "Message",
              "Text"
            ],
            "type": "str"
          }
        },
        "id": "reactflow__edge-URL-Gj8oh{œdataTypeœ:œURLœ,œidœ:œURL-Gj8ohœ,œnameœ:œraw_resultsœ,œoutput_typesœ:[œMessageœ]}-Prompt-7Jzfo{œfieldNameœ:œBASE_COMPONENT_CODEœ,œidœ:œPrompt-7Jzfoœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}",
        "selected": false,
        "source": "URL-Gj8oh",
        "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-Gj8ohœ, œnameœ: œraw_resultsœ, œoutput_typesœ: [œMessageœ]}",
        "target": "Prompt-7Jzfo",
        "targetHandle": "{œfieldNameœ: œBASE_COMPONENT_CODEœ, œidœ: œPrompt-7Jzfoœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}"
      }
    ],
    "nodes": [
      {
        "data": {
          "description": "Retrieves stored chat messages from Langflow tables or an external memory.",
          "display_name": "Chat Memory",
          "id": "Memory-U33nr",
          "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.4.3",
            "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": null,
                "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    documentation: str = \"https://docs.langflow.org/components-helpers#message-history\"\n    icon = \"message-square-more\"\n    name = \"Memory\"\n    default_keys = [\"mode\", \"memory\", \"session_id\"]\n    mode_config = {\n        \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n        \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\", \"session_id\"],\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=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            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\n            if n_messages:\n                stored = stored[-n_messages:]  # Get last N messages first\n\n            if order == \"DESC\":\n                stored = stored[::-1]  # Then reverse if needed\n\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            # For internal memory, we always fetch the last N messages by ordering by DESC\n            stored = await aget_messages(\n                sender=sender_type,\n                sender_name=sender_name,\n                session_id=session_id,\n                limit=10000,\n                order=order,\n            )\n            if n_messages:\n                stored = stored[-n_messages:]  # Get last N messages\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
          },
          "selected_output": "messages_text",
          "type": "Memory"
        },
        "dragging": false,
        "height": 262,
        "id": "Memory-U33nr",
        "measured": {
          "height": 262,
          "width": 320
        },
        "position": {
          "x": 1839.8921277807215,
          "y": 1158.1547287277615
        },
        "positionAbsolute": {
          "x": 1830.6888981898887,
          "y": 946.1205963195098
        },
        "selected": false,
        "type": "genericNode",
        "width": 320
      },
      {
        "data": {
          "description": "Create a prompt template with dynamic variables.",
          "display_name": "Prompt",
          "id": "Prompt-7Jzfo",
          "node": {
            "base_classes": [
              "Message"
            ],
            "beta": false,
            "conditional_paths": [],
            "custom_fields": {
              "template": [
                "BASE_COMPONENT_CODE",
                "CUSTOM_COMPONENT_CODE",
                "EXAMPLE_COMPONENTS",
                "CHAT_HISTORY",
                "USER_INPUT"
              ]
            },
            "description": "Create a prompt template with dynamic variables.",
            "display_name": "Prompt",
            "documentation": "",
            "edited": false,
            "field_order": [
              "template"
            ],
            "frozen": false,
            "icon": "braces",
            "legacy": false,
            "lf_version": "1.4.3",
            "metadata": {
              "code_hash": "3bf0b511e227",
              "module": "langflow.components.prompts.prompt.PromptComponent"
            },
            "output_types": [],
            "outputs": [
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Prompt",
                "group_outputs": false,
                "method": "build_prompt",
                "name": "prompt",
                "selected": "Message",
                "tool_mode": true,
                "types": [
                  "Message"
                ],
                "value": "__UNDEFINED__"
              }
            ],
            "pinned": false,
            "template": {
              "BASE_COMPONENT_CODE": {
                "advanced": false,
                "display_name": "BASE_COMPONENT_CODE",
                "dynamic": false,
                "field_type": "str",
                "fileTypes": [],
                "file_path": "",
                "info": "",
                "input_types": [
                  "Message",
                  "Text"
                ],
                "list": false,
                "load_from_db": false,
                "multiline": true,
                "name": "BASE_COMPONENT_CODE",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "type": "str",
                "value": ""
              },
              "CHAT_HISTORY": {
                "advanced": false,
                "display_name": "CHAT_HISTORY",
                "dynamic": false,
                "field_type": "str",
                "fileTypes": [],
                "file_path": "",
                "info": "",
                "input_types": [
                  "Message",
                  "Text"
                ],
                "list": false,
                "load_from_db": false,
                "multiline": true,
                "name": "CHAT_HISTORY",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "type": "str",
                "value": ""
              },
              "CUSTOM_COMPONENT_CODE": {
                "advanced": false,
                "display_name": "CUSTOM_COMPONENT_CODE",
                "dynamic": false,
                "field_type": "str",
                "fileTypes": [],
                "file_path": "",
                "info": "",
                "input_types": [
                  "Message",
                  "Text"
                ],
                "list": false,
                "load_from_db": false,
                "multiline": true,
                "name": "CUSTOM_COMPONENT_CODE",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "type": "str",
                "value": ""
              },
              "EXAMPLE_COMPONENTS": {
                "advanced": false,
                "display_name": "EXAMPLE_COMPONENTS",
                "dynamic": false,
                "field_type": "str",
                "fileTypes": [],
                "file_path": "",
                "info": "",
                "input_types": [
                  "Message",
                  "Text"
                ],
                "list": false,
                "load_from_db": false,
                "multiline": true,
                "name": "EXAMPLE_COMPONENTS",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "type": "str",
                "value": ""
              },
              "USER_INPUT": {
                "advanced": false,
                "display_name": "USER_INPUT",
                "dynamic": false,
                "field_type": "str",
                "fileTypes": [],
                "file_path": "",
                "info": "",
                "input_types": [
                  "Message",
                  "Text"
                ],
                "list": false,
                "load_from_db": false,
                "multiline": true,
                "name": "USER_INPUT",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "type": "str",
                "value": ""
              },
              "_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.prompts.api_utils import process_prompt_template\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import MessageTextInput, Output, PromptInput\nfrom langflow.schema.message import Message\nfrom langflow.template.utils import update_template_values\n\n\nclass PromptComponent(Component):\n    display_name: str = \"Prompt\"\n    description: str = \"Create a prompt template with dynamic variables.\"\n    icon = \"braces\"\n    trace_type = \"prompt\"\n    name = \"Prompt\"\n\n    inputs = [\n        PromptInput(name=\"template\", display_name=\"Template\"),\n        MessageTextInput(\n            name=\"tool_placeholder\",\n            display_name=\"Tool Placeholder\",\n            tool_mode=True,\n            advanced=True,\n            info=\"A placeholder input for tool mode.\",\n        ),\n    ]\n\n    outputs = [\n        Output(display_name=\"Prompt\", name=\"prompt\", method=\"build_prompt\"),\n    ]\n\n    async def build_prompt(self) -> Message:\n        prompt = Message.from_template(**self._attributes)\n        self.status = prompt.text\n        return prompt\n\n    def _update_template(self, frontend_node: dict):\n        prompt_template = frontend_node[\"template\"][\"template\"][\"value\"]\n        custom_fields = frontend_node[\"custom_fields\"]\n        frontend_node_template = frontend_node[\"template\"]\n        _ = process_prompt_template(\n            template=prompt_template,\n            name=\"template\",\n            custom_fields=custom_fields,\n            frontend_node_template=frontend_node_template,\n        )\n        return frontend_node\n\n    async def update_frontend_node(self, new_frontend_node: dict, current_frontend_node: dict):\n        \"\"\"This function is called after the code validation is done.\"\"\"\n        frontend_node = await super().update_frontend_node(new_frontend_node, current_frontend_node)\n        template = frontend_node[\"template\"][\"template\"][\"value\"]\n        # Kept it duplicated for backwards compatibility\n        _ = process_prompt_template(\n            template=template,\n            name=\"template\",\n            custom_fields=frontend_node[\"custom_fields\"],\n            frontend_node_template=frontend_node[\"template\"],\n        )\n        # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n        # and update the frontend_node with those values\n        update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n        return frontend_node\n\n    def _get_fallback_input(self, **kwargs):\n        return DefaultPromptField(**kwargs)\n"
              },
              "template": {
                "_input_type": "PromptInput",
                "advanced": false,
                "display_name": "Template",
                "dynamic": false,
                "info": "",
                "list": false,
                "load_from_db": false,
                "name": "template",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "tool_mode": false,
                "trace_as_input": true,
                "type": "prompt",
                "value": "<Instructions>\nYou are an AI assistant specialized in creating Langflow components based on user requirements. Your task is to generate the code for a custom Langflow component according to the user's specifications.\n\nFirst, review the following code snippets for reference:\n\n<base_component>\n{BASE_COMPONENT_CODE}\n</base_component>\n\n<custom_component>\n{CUSTOM_COMPONENT_CODE}\n</custom_component>\n\n<example_components>\n{EXAMPLE_COMPONENTS}\n</example_components>\n\nNow, follow these steps to create a custom Langflow component:\n\n1. Analyze the user's input to determine the requirements for the component.\n2. Use an <inner_monologue> section to plan out the component structure and features based on the user's requirements.\n3. Generate the code for the custom component, using the provided code snippets as reference and inspiration.\n4. Provide a brief explanation of the component's functionality and how to use it.\n\nHere's the chat history and user input:\n\n<ChatHistory>\n{CHAT_HISTORY}\n</ChatHistory>\n\n<UserInput>\n{USER_INPUT}\n</UserInput>\n\nBased on the user's input, create a custom Langflow component that meets their requirements. Your response should include:\n\n1. <inner_monologue>\n   Use this section to analyze the user's requirements and plan the component structure.\n</inner_monologue>\n\n2. <component_code>\n   Generate the complete code for the custom Langflow component here. Show it in a Markdown code tab.\n</component_code>\n\n3. <explanation>\n   Provide a brief explanation of the component's functionality and how to use it.\n</explanation>\n\nRemember to:\n- Use the provided code snippets as a reference, but create a unique component tailored to the user's needs.\n- Include all necessary imports and class definitions.\n- Implement the required inputs, outputs, and any additional features specified by the user.\n- Use clear and descriptive variable names and comments to enhance code readability.\n- Ensure that the component follows Langflow best practices and conventions.\n\nIf the user's input is unclear or lacks specific details, make reasonable assumptions based on the context and explain these assumptions in your response.\n\n</Instructions>"
              },
              "tool_placeholder": {
                "_input_type": "MessageTextInput",
                "advanced": true,
                "display_name": "Tool Placeholder",
                "dynamic": false,
                "info": "A placeholder input for tool mode.",
                "input_types": [
                  "Message"
                ],
                "list": false,
                "load_from_db": false,
                "name": "tool_placeholder",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "tool_mode": true,
                "trace_as_input": true,
                "trace_as_metadata": true,
                "type": "str",
                "value": ""
              }
            },
            "tool_mode": false
          },
          "selected_output": "prompt",
          "type": "Prompt"
        },
        "dragging": false,
        "height": 685,
        "id": "Prompt-7Jzfo",
        "measured": {
          "height": 685,
          "width": 320
        },
        "position": {
          "x": 2214.0288118788944,
          "y": 514.3016755222201
        },
        "positionAbsolute": {
          "x": 2219.5265974825707,
          "y": 521.6320563271215
        },
        "selected": false,
        "type": "genericNode",
        "width": 320
      },
      {
        "data": {
          "id": "note-x5NN0",
          "node": {
            "description": "# 🛠️ Custom Component Generator 🚀\n\nHi! I'm here to help you create custom components for Langflow. Think of me as your technical partner who can help turn your ideas into working components! \n\n## 🎯 How to Work With Me\n\n1. Add your **Anthropic API Key** to the **Language Model** Component\n\n2. 💭 Tell Me What You Want to Build.\nSimply describe what you want your component to do in plain English. For example:\n- \"I need a component that sends Slack messages\"\n- \"I want to create a tool that can process CSV files\"\n- \"I need something that can translate text\"\n\n\nReady to build something awesome? 🚀 Let's get started!",
            "display_name": "",
            "documentation": "",
            "template": {}
          },
          "type": "note"
        },
        "dragging": false,
        "height": 605,
        "id": "note-x5NN0",
        "measured": {
          "height": 605,
          "width": 626
        },
        "position": {
          "x": 730.5474183114914,
          "y": 395.14430009157354
        },
        "positionAbsolute": {
          "x": 807.6293964045135,
          "y": 605.6504562080672
        },
        "resizing": false,
        "selected": false,
        "style": {
          "height": 573,
          "width": 324
        },
        "type": "noteNode",
        "width": 626
      },
      {
        "data": {
          "id": "URL-Gj8oh",
          "node": {
            "base_classes": [
              "Data",
              "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"
            ],
            "frozen": false,
            "icon": "layout-template",
            "legacy": false,
            "lf_version": "1.4.3",
            "metadata": {},
            "output_types": [],
            "outputs": [
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Result",
                "group_outputs": false,
                "method": "fetch_content",
                "name": "page_results",
                "tool_mode": true,
                "types": [
                  "DataFrame"
                ],
                "value": "__UNDEFINED__"
              },
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Raw Result",
                "group_outputs": false,
                "method": "as_message",
                "name": "raw_results",
                "selected": "Message",
                "tool_mode": true,
                "types": [
                  "Message"
                ],
                "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,
                "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"
                ],
                "placeholder": "",
                "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,
                  "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
              },
              "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,
                "load_from_db": false,
                "name": "urls",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "tool_mode": true,
                "trace_as_input": true,
                "trace_as_metadata": true,
                "type": "str",
                "value": [
                  "https://raw.githubusercontent.com/langflow-ai/langflow/refs/heads/main/src/backend/base/langflow/custom/custom_component/component.py"
                ]
              },
              "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": false
          },
          "selected_output": "raw_results",
          "type": "URL"
        },
        "dragging": false,
        "height": 365,
        "id": "URL-Gj8oh",
        "measured": {
          "height": 365,
          "width": 320
        },
        "position": {
          "x": 1422.737604307548,
          "y": 85.36729017597193
        },
        "positionAbsolute": {
          "x": 1436.3617127766433,
          "y": 264.218898085405
        },
        "selected": false,
        "type": "genericNode",
        "width": 320
      },
      {
        "data": {
          "id": "URL-LiTXv",
          "node": {
            "base_classes": [
              "Data",
              "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"
            ],
            "frozen": false,
            "icon": "layout-template",
            "legacy": false,
            "lf_version": "1.4.3",
            "metadata": {},
            "output_types": [],
            "outputs": [
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Result",
                "group_outputs": false,
                "method": "fetch_content",
                "name": "page_results",
                "tool_mode": true,
                "types": [
                  "DataFrame"
                ],
                "value": "__UNDEFINED__"
              },
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Raw Result",
                "group_outputs": false,
                "method": "as_message",
                "name": "raw_results",
                "selected": "Message",
                "tool_mode": true,
                "types": [
                  "Message"
                ],
                "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,
                "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"
                ],
                "placeholder": "",
                "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,
                  "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
              },
              "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,
                "load_from_db": false,
                "name": "urls",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "tool_mode": true,
                "trace_as_input": true,
                "trace_as_metadata": true,
                "type": "str",
                "value": [
                  "https://github.com/langflow-ai/langflow/blob/main/src/lfx/src/lfx/base/agents/agent.py",
                  "https://github.com/langflow-ai/langflow/blob/main/src/lfx/src/lfx/components/llm_operations/structured_output.py",
                  "https://raw.githubusercontent.com/langflow-ai/langflow/refs/heads/main/src/lfx/src/lfx/components/tools/calculator.py",
                  "https://raw.githubusercontent.com/langflow-ai/langflow/refs/heads/main/src/lfx/src/lfx/components/tavily/tavily_search.py",
                  "https://raw.githubusercontent.com/langflow-ai/langflow/refs/heads/main/src/lfx/src/lfx/components/ollama/ollama.py",
                  "https://raw.githubusercontent.com/langflow-ai/langflow/refs/heads/main/src/lfx/src/lfx/components/flow_controls/conditional_router.py",
                  "https://raw.githubusercontent.com/langflow-ai/langflow/refs/heads/main/src/lfx/src/lfx/components/files_and_knowledge/file.py"
                ]
              },
              "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": false
          },
          "selected_output": "raw_results",
          "type": "URL"
        },
        "dragging": false,
        "height": 661,
        "id": "URL-LiTXv",
        "measured": {
          "height": 661,
          "width": 320
        },
        "position": {
          "x": 1824.3180693088113,
          "y": 284.41077226342696
        },
        "positionAbsolute": {
          "x": 1831.5895760156684,
          "y": 245.62940316018893
        },
        "selected": false,
        "type": "genericNode",
        "width": 320
      },
      {
        "data": {
          "id": "URL-E6QCv",
          "node": {
            "base_classes": [
              "Data",
              "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"
            ],
            "frozen": false,
            "icon": "layout-template",
            "legacy": false,
            "lf_version": "1.4.3",
            "metadata": {},
            "output_types": [],
            "outputs": [
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Result",
                "group_outputs": false,
                "method": "fetch_content",
                "name": "page_results",
                "tool_mode": true,
                "types": [
                  "DataFrame"
                ],
                "value": "__UNDEFINED__"
              },
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Raw Result",
                "group_outputs": false,
                "method": "as_message",
                "name": "raw_results",
                "selected": "Message",
                "tool_mode": true,
                "types": [
                  "Message"
                ],
                "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,
                "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"
                ],
                "placeholder": "",
                "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,
                  "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
              },
              "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,
                "load_from_db": false,
                "name": "urls",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "tool_mode": true,
                "trace_as_input": true,
                "trace_as_metadata": true,
                "type": "str",
                "value": [
                  "https://raw.githubusercontent.com/langflow-ai/langflow/refs/heads/main/src/backend/base/langflow/components/custom_component/custom_component.py"
                ]
              },
              "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": false
          },
          "selected_output": "raw_results",
          "type": "URL"
        },
        "dragging": false,
        "height": 365,
        "id": "URL-E6QCv",
        "measured": {
          "height": 365,
          "width": 320
        },
        "position": {
          "x": 1503.311191099216,
          "y": 859.9645996406584
        },
        "positionAbsolute": {
          "x": 1436.982480021523,
          "y": 651.1409296825055
        },
        "selected": false,
        "type": "genericNode",
        "width": 320
      },
      {
        "data": {
          "id": "ChatInput-u8rae",
          "node": {
            "base_classes": [
              "Message"
            ],
            "beta": false,
            "category": "inputs",
            "conditional_paths": [],
            "custom_fields": {},
            "description": "Get chat inputs from the Playground.",
            "display_name": "Chat Input",
            "documentation": "",
            "edited": false,
            "field_order": [
              "input_value",
              "should_store_message",
              "sender",
              "sender_name",
              "session_id",
              "files",
              "background_color",
              "chat_icon",
              "text_color"
            ],
            "frozen": false,
            "icon": "MessagesSquare",
            "key": "ChatInput",
            "legacy": false,
            "lf_version": "1.4.3",
            "metadata": {},
            "minimized": true,
            "output_types": [],
            "outputs": [
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Chat Message",
                "group_outputs": false,
                "method": "message_response",
                "name": "message",
                "selected": "Message",
                "tool_mode": true,
                "types": [
                  "Message"
                ],
                "value": "__UNDEFINED__"
              }
            ],
            "pinned": false,
            "score": 0.0020353564437605998,
            "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.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import (\n    DropdownInput,\n    FileInput,\n    MessageTextInput,\n    MultilineInput,\n    Output,\n)\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import (\n    MESSAGE_SENDER_AI,\n    MESSAGE_SENDER_NAME_USER,\n    MESSAGE_SENDER_USER,\n)\n\n\nclass ChatInput(ChatComponent):\n    display_name = \"Chat Input\"\n    description = \"Get chat inputs from the Playground.\"\n    documentation: str = \"https://docs.langflow.org/components-io#chat-input\"\n    icon = \"MessagesSquare\"\n    name = \"ChatInput\"\n    minimized = True\n\n    inputs = [\n        MultilineInput(\n            name=\"input_value\",\n            display_name=\"Input Text\",\n            value=\"\",\n            info=\"Message to be passed as input.\",\n            input_types=[],\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_USER,\n            info=\"Type of sender.\",\n            advanced=True,\n        ),\n        MessageTextInput(\n            name=\"sender_name\",\n            display_name=\"Sender Name\",\n            info=\"Name of the sender.\",\n            value=MESSAGE_SENDER_NAME_USER,\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        FileInput(\n            name=\"files\",\n            display_name=\"Files\",\n            file_types=TEXT_FILE_TYPES + IMG_FILE_TYPES,\n            info=\"Files to be sent with the message.\",\n            advanced=True,\n            is_list=True,\n            temp_file=True,\n        ),\n    ]\n    outputs = [\n        Output(display_name=\"Chat Message\", name=\"message\", method=\"message_response\"),\n    ]\n\n    async def message_response(self) -> Message:\n        # Ensure files is a list and filter out empty/None values\n        files = self.files if self.files else []\n        if files and not isinstance(files, list):\n            files = [files]\n        files = [f for f in files if f is not None and f != \"\"]\n\n        message = await Message.create(\n            text=self.input_value,\n            sender=self.sender,\n            sender_name=self.sender_name,\n            session_id=self.session_id,\n            files=files,\n        )\n        if self.session_id and isinstance(message, Message) and self.should_store_message:\n            stored_message = await self.send_message(\n                message,\n            )\n            self.message.value = stored_message\n            message = stored_message\n\n        self.status = message\n        return message\n"
              },
              "files": {
                "_input_type": "FileInput",
                "advanced": true,
                "display_name": "Files",
                "dynamic": false,
                "fileTypes": [
                  "csv",
                  "json",
                  "pdf",
                  "txt",
                  "md",
                  "mdx",
                  "yaml",
                  "yml",
                  "xml",
                  "html",
                  "htm",
                  "docx",
                  "py",
                  "sh",
                  "sql",
                  "js",
                  "ts",
                  "tsx",
                  "jpg",
                  "jpeg",
                  "png",
                  "bmp",
                  "image"
                ],
                "file_path": "",
                "info": "Files to be sent with the message.",
                "list": true,
                "list_add_label": "Add More",
                "name": "files",
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "trace_as_metadata": true,
                "type": "file",
                "value": ""
              },
              "input_value": {
                "_input_type": "MultilineInput",
                "advanced": false,
                "copy_field": false,
                "display_name": "Input Text",
                "dynamic": false,
                "info": "Message to be passed as input.",
                "input_types": [],
                "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": false,
                "trace_as_input": true,
                "trace_as_metadata": true,
                "type": "str",
                "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": "User"
              },
              "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": "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,
                "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
              }
            },
            "tool_mode": false
          },
          "selected_output": "message",
          "showNode": false,
          "type": "ChatInput"
        },
        "dragging": false,
        "id": "ChatInput-u8rae",
        "measured": {
          "height": 48,
          "width": 192
        },
        "position": {
          "x": 1570.5862655382064,
          "y": 1294.1398515394083
        },
        "selected": false,
        "type": "genericNode"
      },
      {
        "data": {
          "id": "ChatOutput-qF9Bn",
          "node": {
            "base_classes": [
              "Message"
            ],
            "beta": false,
            "category": "outputs",
            "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",
            "key": "ChatOutput",
            "legacy": false,
            "metadata": {},
            "minimized": true,
            "output_types": [],
            "outputs": [
              {
                "allows_loop": false,
                "cache": true,
                "display_name": "Output Message",
                "group_outputs": false,
                "method": "message_response",
                "name": "message",
                "selected": "Message",
                "tool_mode": true,
                "types": [
                  "Message"
                ],
                "value": "__UNDEFINED__"
              }
            ],
            "pinned": false,
            "score": 0.003169567463043492,
            "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 collections.abc import Generator\nfrom typing import Any\n\nimport orjson\nfrom fastapi.encoders import jsonable_encoder\n\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.helpers.data import safe_convert\nfrom langflow.inputs.inputs import BoolInput, DropdownInput, HandleInput, MessageTextInput\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.template.field.base import Output\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    documentation: str = \"https://docs.langflow.org/components-io#chat-output\"\n    icon = \"MessagesSquare\"\n    name = \"ChatOutput\"\n    minimized = True\n\n    inputs = [\n        HandleInput(\n            name=\"input_value\",\n            display_name=\"Inputs\",\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    ]\n    outputs = [\n        Output(\n            display_name=\"Output 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\n        # Get source properties\n        source, icon, display_name, source_id = self.get_properties_from_source_component()\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\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 _serialize_data(self, data: Data) -> str:\n        \"\"\"Serialize Data object to JSON string.\"\"\"\n        # Convert data.data to JSON-serializable format\n        serializable_data = jsonable_encoder(data.data)\n        # Serialize with orjson, enabling pretty printing with indentation\n        json_bytes = orjson.dumps(serializable_data, option=orjson.OPT_INDENT_2)\n        # Convert bytes to string and wrap in Markdown code blocks\n        return \"```json\\n\" + json_bytes.decode(\"utf-8\") + \"\\n```\"\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 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            clean_data: bool = getattr(self, \"clean_data\", False)\n            return \"\\n\".join([safe_convert(item, clean_data=clean_data) for item in self.input_value])\n        if isinstance(self.input_value, Generator):\n            return self.input_value\n        return 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": "Inputs",
                "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
              }
            },
            "tool_mode": false
          },
          "showNode": true,
          "type": "ChatOutput"
        },
        "dragging": false,
        "id": "ChatOutput-qF9Bn",
        "measured": {
          "height": 165,
          "width": 320
        },
        "position": {
          "x": 2987.5763483928145,
          "y": 865.2708447719162
        },
        "selected": false,
        "type": "genericNode"
      },
      {
        "data": {
          "id": "LanguageModelComponent-muTzI",
          "node": {
            "base_classes": [
              "LanguageModel",
              "Message"
            ],
            "beta": false,
            "category": "models",
            "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",
            "key": "LanguageModelComponent",
            "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",
                "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,
            "score": 0.28173906304863156,
            "template": {
              "_type": "Component",
              "api_key": {
                "_input_type": "SecretStrInput",
                "advanced": false,
                "display_name": "Anthropic 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": "ANTHROPIC_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_CHAT_MODEL_NAMES, OPENAI_REASONING_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    documentation: str = \"https://docs.langflow.org/components-models\"\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_CHAT_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n            value=OPENAI_CHAT_MODEL_NAMES[0],\n            info=\"Select the model to use\",\n            real_time_refresh=True,\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=False,\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\n            if model_name in OPENAI_REASONING_MODEL_NAMES:\n                # reasoning models do not support temperature (yet)\n                temperature = None\n\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_CHAT_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES\n                build_config[\"model_name\"][\"value\"] = OPENAI_CHAT_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        elif field_name == \"model_name\" and field_value.startswith(\"o1\") and self.provider == \"OpenAI\":\n            # Hide system_message for o1 models - currently unsupported\n            if \"system_message\" in build_config:\n                build_config[\"system_message\"][\"show\"] = False\n        elif field_name == \"model_name\" and not field_value.startswith(\"o1\") and \"system_message\" in build_config:\n            build_config[\"system_message\"][\"show\"] = True\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": [
                  "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"
                ],
                "options_metadata": [],
                "placeholder": "",
                "required": false,
                "show": true,
                "title_case": false,
                "toggle": false,
                "tool_mode": false,
                "trace_as_metadata": true,
                "type": "str",
                "value": "claude-opus-4-20250514"
              },
              "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": "Google"
                  }
                ],
                "placeholder": "",
                "real_time_refresh": true,
                "required": false,
                "show": true,
                "title_case": false,
                "toggle": false,
                "tool_mode": false,
                "trace_as_metadata": true,
                "type": "str",
                "value": "Anthropic"
              },
              "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": true,
                "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
          },
          "selected_output": "text_output",
          "showNode": true,
          "type": "LanguageModelComponent"
        },
        "dragging": false,
        "id": "LanguageModelComponent-muTzI",
        "measured": {
          "height": 449,
          "width": 320
        },
        "position": {
          "x": 2595.812486589649,
          "y": 559.0945152239169
        },
        "selected": false,
        "type": "genericNode"
      }
    ],
    "viewport": {
      "x": -169.88117007333017,
      "y": -14.61264877721112,
      "zoom": 0.7334501147704762
    }
  },
  "description": "Generates well-structured code for custom components following Langflow's specifications.",
  "endpoint_name": null,
  "id": "81b54c06-58c5-4e91-a228-b5aaf7ffa66d",
  "is_component": false,
  "last_tested_version": "1.4.3",
  "name": "Custom Component Generator",
  "tags": [
    "coding",
    "web-scraping"
  ]
}