From 38d5885fa3cd752a37d2185bfbfa0144184086f2 Mon Sep 17 00:00:00 2001 From: Edwin Jose Date: Wed, 25 Jun 2025 11:33:57 -0500 Subject: [PATCH] refactor(agent): standardize memory handling and update chat history logic (#8715) * update chat history * update to agents * Update Simple Agent.json * update to templates * ruff errors * Update agent.py * Update test_agent_component.py * [autofix.ci] apply automated fixes * update templates * test fix --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Mike Fortman --- .../base/langflow/base/agents/agent.py | 5 +- .../base/langflow/components/agents/agent.py | 34 +- .../langflow/components/helpers/memory.py | 15 +- .../custom/custom_component/component.py | 2 +- .../Custom Component Maker.json | 2 +- .../starter_projects/Financial Agent.json | 4247 --------------- .../Instagram Copywriter.json | 2123 +++----- .../starter_projects/Invoice Summarizer.json | 391 +- .../starter_projects/Market Research.json | 2192 ++++---- .../starter_projects/Meeting Summary.json | 1812 +++---- .../starter_projects/Memory Chatbot.json | 2 +- .../starter_projects/News Aggregator.json | 1523 +++--- .../starter_projects/Pokédex Agent.json | 394 +- .../starter_projects/Price Deal Finder.json | 352 +- .../starter_projects/Research Agent.json | 3042 +++++------ .../starter_projects/SaaS Pricing.json | 1310 ++--- .../starter_projects/Search agent.json | 527 +- .../Sequential Tasks Agents.json | 1448 ++--- .../starter_projects/Simple Agent.json | 460 +- .../starter_projects/Social Media Agent.json | 393 +- .../Travel Planning Agents.json | 4685 +++++++---------- .../starter_projects/Youtube Analysis.json | 1201 ++--- .../components/agents/test_agent_component.py | 6 +- .../core/integrations/Financial Agent.spec.ts | 78 - .../core/integrations/Market Research.spec.ts | 11 - 25 files changed, 8672 insertions(+), 17583 deletions(-) delete mode 100644 src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json delete mode 100644 src/frontend/tests/core/integrations/Financial Agent.spec.ts diff --git a/src/backend/base/langflow/base/agents/agent.py b/src/backend/base/langflow/base/agents/agent.py index df988a1e6..a04241a84 100644 --- a/src/backend/base/langflow/base/agents/agent.py +++ b/src/backend/base/langflow/base/agents/agent.py @@ -139,7 +139,10 @@ class LCAgentComponent(Component): if hasattr(self, "system_prompt"): input_dict["system_prompt"] = self.system_prompt if hasattr(self, "chat_history") and self.chat_history: - input_dict["chat_history"] = data_to_messages(self.chat_history) + if isinstance(self.chat_history, Data): + input_dict["chat_history"] = data_to_messages(self.chat_history) + if all(isinstance(m, Message) for m in self.chat_history): + input_dict["chat_history"] = data_to_messages([m.to_data() for m in self.chat_history]) if hasattr(self, "graph"): session_id = self.graph.session_id diff --git a/src/backend/base/langflow/components/agents/agent.py b/src/backend/base/langflow/components/agents/agent.py index 84ab8a074..8d7cfc2ba 100644 --- a/src/backend/base/langflow/components/agents/agent.py +++ b/src/backend/base/langflow/components/agents/agent.py @@ -16,7 +16,7 @@ from langflow.components.langchain_utilities.tool_calling import ToolCallingAgen from langflow.custom.custom_component.component import _get_component_toolkit from langflow.custom.utils import update_component_build_config from langflow.field_typing import Tool -from langflow.io import BoolInput, DropdownInput, MultilineInput, Output +from langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output from langflow.logging import logger from langflow.schema.dotdict import dotdict from langflow.schema.message import Message @@ -27,6 +27,9 @@ def set_advanced_true(component_input): return component_input +MODEL_PROVIDERS_LIST = ["Anthropic", "Google Generative AI", "Groq", "OpenAI"] + + class AgentComponent(ToolCallingAgentComponent): display_name: str = "Agent" description: str = "Define the agent's instructions, then enter a task to complete using tools." @@ -41,11 +44,11 @@ class AgentComponent(ToolCallingAgentComponent): name="agent_llm", display_name="Model Provider", info="The provider of the language model that the agent will use to generate responses.", - options=[*sorted(MODEL_PROVIDERS), "Custom"], + options=[*MODEL_PROVIDERS_LIST, "Custom"], value="OpenAI", real_time_refresh=True, input_types=[], - options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{"icon": "brain"}], + options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{"icon": "brain"}], ), *MODEL_PROVIDERS_DICT["OpenAI"]["inputs"], MultilineInput( @@ -55,8 +58,17 @@ class AgentComponent(ToolCallingAgentComponent): value="You are a helpful assistant that can use tools to answer questions and perform tasks.", advanced=False, ), + IntInput( + name="n_messages", + display_name="Number of Chat History Messages", + value=100, + info="Number of chat history messages to retrieve.", + advanced=True, + show=True, + ), *LCToolsAgentComponent._base_inputs, - *memory_inputs, + # removed memory inputs from agent component + # *memory_inputs, BoolInput( name="add_current_date_tool", display_name="Current Date", @@ -78,6 +90,8 @@ class AgentComponent(ToolCallingAgentComponent): # Get memory data self.chat_history = await self.get_memory_data() + if isinstance(self.chat_history, Message): + self.chat_history = [self.chat_history] # Add current date tool if enabled if self.add_current_date_tool: @@ -112,13 +126,11 @@ class AgentComponent(ToolCallingAgentComponent): raise async def get_memory_data(self): - memory_kwargs = { - component_input.name: getattr(self, f"{component_input.name}") for component_input in self.memory_inputs - } - # filter out empty values - memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None} - - return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages() + return ( + await MemoryComponent(**self.get_base_args()) + .set(session_id=self.graph.session_id, order="Ascending", n_messages=self.n_messages) + .retrieve_messages() + ) def get_llm(self): if not isinstance(self.agent_llm, str): diff --git a/src/backend/base/langflow/components/helpers/memory.py b/src/backend/base/langflow/components/helpers/memory.py index 7021ff91c..9b592f9d8 100644 --- a/src/backend/base/langflow/components/helpers/memory.py +++ b/src/backend/base/langflow/components/helpers/memory.py @@ -76,7 +76,7 @@ class MemoryComponent(Component): value=100, info="Number of messages to retrieve.", advanced=True, - show=False, + show=True, ), MessageTextInput( name="session_id", @@ -197,28 +197,33 @@ class MemoryComponent(Component): stored = await self.memory.aget_messages() # langchain memories are supposed to return messages in ascending order + if order == "DESC": stored = stored[::-1] if n_messages: - stored = stored[:n_messages] + stored = stored[-n_messages:] if order == "ASC" else stored[:n_messages] stored = [Message.from_lc_message(m) for m in stored] if sender_type: expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER stored = [m for m in stored if m.type == expected_type] else: + # For internal memory, we always fetch the last N messages by ordering by DESC stored = await aget_messages( sender=sender_type, sender_name=sender_name, session_id=session_id, - limit=n_messages, + limit=10000, order=order, ) - self.status = stored + if n_messages: + stored = stored[-n_messages:] if order == "ASC" else stored[:n_messages] + + # self.status = stored return cast(Data, stored) async def retrieve_messages_as_text(self) -> Message: stored_text = data_to_text(self.template, await self.retrieve_messages()) - self.status = stored_text + # self.status = stored_text return Message(text=stored_text) async def retrieve_messages_dataframe(self) -> DataFrame: diff --git a/src/backend/base/langflow/custom/custom_component/component.py b/src/backend/base/langflow/custom/custom_component/component.py index 1b0e60a9b..a26172a25 100644 --- a/src/backend/base/langflow/custom/custom_component/component.py +++ b/src/backend/base/langflow/custom/custom_component/component.py @@ -215,7 +215,7 @@ class Component(CustomComponent): """ return { "_user_id": self.user_id, - "_session_id": self.session_id, + "_session_id": self.graph.session_id, "_tracing_service": self._tracing_service, } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json b/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json index d8c1a1b4e..ad1fecfb1 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Maker.json @@ -287,7 +287,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from typing import Any, cast\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs.inputs import DropdownInput, HandleInput, IntInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.memory import aget_messages, astore_message\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\nfrom langflow.utils.component_utils import set_current_fields, set_field_display\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Stores or retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n default_keys = [\"mode\", \"memory\"]\n mode_config = {\n \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\"],\n }\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Retrieve\", \"Store\"],\n value=\"Retrieve\",\n info=\"Operation mode: Store messages or Retrieve messages.\",\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The chat message to be stored.\",\n tool_mode=True,\n dynamic=True,\n show=False,\n ),\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"sender_type\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender\",\n display_name=\"Sender\",\n info=\"The sender of the message. Might be Machine or User. \"\n \"If empty, the current sender parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n show=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n show=False,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n value=\"\",\n advanced=True,\n ),\n DropdownInput(\n name=\"order\",\n display_name=\"Order\",\n options=[\"Ascending\", \"Descending\"],\n value=\"Ascending\",\n info=\"Order of the messages.\",\n advanced=True,\n tool_mode=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {sender} or any other key in the message data.\",\n value=\"{sender_name}: {text}\",\n advanced=True,\n show=False,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Message\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True),\n Output(display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True),\n ]\n\n def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:\n \"\"\"Dynamically show only the relevant output based on the selected output type.\"\"\"\n if field_name == \"mode\":\n # Start with empty outputs\n frontend_node[\"outputs\"] = []\n if field_value == \"Store\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Stored Messages\",\n name=\"stored_messages\",\n method=\"store_message\",\n hidden=True,\n dynamic=True,\n )\n ]\n if field_value == \"Retrieve\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Messages\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True\n ),\n Output(\n display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True\n ),\n ]\n return frontend_node\n\n async def store_message(self) -> Message:\n message = Message(text=self.message) if isinstance(self.message, str) else self.message\n\n message.session_id = self.session_id or message.session_id\n message.sender = self.sender or message.sender or MESSAGE_SENDER_AI\n message.sender_name = self.sender_name or message.sender_name or MESSAGE_SENDER_NAME_AI\n\n stored_messages: list[Message] = []\n\n if self.memory:\n self.memory.session_id = message.session_id\n lc_message = message.to_lc_message()\n await self.memory.aadd_messages([lc_message])\n\n stored_messages = await self.memory.aget_messages() or []\n\n stored_messages = [Message.from_lc_message(m) for m in stored_messages] if stored_messages else []\n\n if message.sender:\n stored_messages = [m for m in stored_messages if m.sender == message.sender]\n else:\n await astore_message(message, flow_id=self.graph.flow_id)\n stored_messages = (\n await aget_messages(\n session_id=message.session_id, sender_name=message.sender_name, sender=message.sender\n )\n or []\n )\n\n if not stored_messages:\n msg = \"No messages were stored. Please ensure that the session ID and sender are properly set.\"\n raise ValueError(msg)\n\n stored_message = stored_messages[0]\n self.status = stored_message\n return stored_message\n\n async def retrieve_messages(self) -> Data:\n sender_type = self.sender_type\n sender_name = self.sender_name\n session_id = self.session_id\n n_messages = self.n_messages\n order = \"DESC\" if self.order == \"Descending\" else \"ASC\"\n\n if sender_type == \"Machine and User\":\n sender_type = None\n\n if self.memory and not hasattr(self.memory, \"aget_messages\"):\n memory_name = type(self.memory).__name__\n err_msg = f\"External Memory object ({memory_name}) must have 'aget_messages' method.\"\n raise AttributeError(err_msg)\n # Check if n_messages is None or 0\n if n_messages == 0:\n stored = []\n elif self.memory:\n # override session_id\n self.memory.session_id = session_id\n\n stored = await self.memory.aget_messages()\n # langchain memories are supposed to return messages in ascending order\n if order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender_type:\n expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n stored = await aget_messages(\n sender=sender_type,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n self.status = stored\n return cast(Data, stored)\n\n async def retrieve_messages_as_text(self) -> Message:\n stored_text = data_to_text(self.template, await self.retrieve_messages())\n self.status = stored_text\n return Message(text=stored_text)\n\n async def retrieve_messages_dataframe(self) -> DataFrame:\n \"\"\"Convert the retrieved messages into a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the message data.\n \"\"\"\n messages = await self.retrieve_messages()\n return DataFrame(messages)\n\n def update_build_config(\n self,\n build_config: dotdict,\n field_value: Any, # noqa: ARG002\n field_name: str | None = None, # noqa: ARG002\n ) -> dotdict:\n return set_current_fields(\n build_config=build_config,\n action_fields=self.mode_config,\n selected_action=build_config[\"mode\"][\"value\"],\n default_fields=self.default_keys,\n func=set_field_display,\n )\n" + "value": "from typing import Any, cast\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs.inputs import DropdownInput, HandleInput, IntInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.memory import aget_messages, astore_message\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\nfrom langflow.utils.component_utils import set_current_fields, set_field_display\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Stores or retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n default_keys = [\"mode\", \"memory\"]\n mode_config = {\n \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\"],\n }\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Retrieve\", \"Store\"],\n value=\"Retrieve\",\n info=\"Operation mode: Store messages or Retrieve messages.\",\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The chat message to be stored.\",\n tool_mode=True,\n dynamic=True,\n show=False,\n ),\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"sender_type\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender\",\n display_name=\"Sender\",\n info=\"The sender of the message. Might be Machine or User. \"\n \"If empty, the current sender parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n show=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n show=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 order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[-n_messages:] if order == \"ASC\" else stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender_type:\n expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n # 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:] if order == \"ASC\" else stored[: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", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json deleted file mode 100644 index 05b6e0d58..000000000 --- a/src/backend/base/langflow/initial_setup/starter_projects/Financial Agent.json +++ /dev/null @@ -1,4247 +0,0 @@ -{ - "data": { - "edges": [ - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "SambaNovaModel", - "id": "SambaNovaModel-8WRTL", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-Cvbe8", - "inputTypes": [ - "Data", - "DataFrame", - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-SambaNovaModel-8WRTL{œdataTypeœ:œSambaNovaModelœ,œidœ:œSambaNovaModel-8WRTLœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Cvbe8{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Cvbe8œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "SambaNovaModel-8WRTL", - "sourceHandle": "{œdataTypeœ: œSambaNovaModelœ, œidœ: œSambaNovaModel-8WRTLœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-Cvbe8", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Cvbe8œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-qozug", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-J7aBZ", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-qozug{œdataTypeœ:œChatInputœ,œidœ:œChatInput-qozugœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-J7aBZ{œfieldNameœ:œinput_valueœ,œidœ:œAgent-J7aBZœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-qozug", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-qozugœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-J7aBZ", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-J7aBZœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "TavilySearchComponent", - "id": "TavilySearchComponent-5hDm1", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-J7aBZ", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-TavilySearchComponent-5hDm1{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-5hDm1œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-J7aBZ{œfieldNameœ:œtoolsœ,œidœ:œAgent-J7aBZœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "TavilySearchComponent-5hDm1", - "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-5hDm1œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-J7aBZ", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-J7aBZœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "URL", - "id": "URL-mbCdn", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-oCAnt", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-URL-mbCdn{œdataTypeœ:œURLœ,œidœ:œURL-mbCdnœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-oCAnt{œfieldNameœ:œtoolsœ,œidœ:œAgent-oCAntœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "URL-mbCdn", - "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-mbCdnœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-oCAnt", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-oCAntœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-qozug", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-oCAnt", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-qozug{œdataTypeœ:œChatInputœ,œidœ:œChatInput-qozugœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-oCAnt{œfieldNameœ:œinput_valueœ,œidœ:œAgent-oCAntœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-qozug", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-qozugœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-oCAnt", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-oCAntœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Agent", - "id": "Agent-oCAnt", - "name": "response", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "first_text", - "id": "Prompt-GCeTu", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Agent-oCAnt{œdataTypeœ:œAgentœ,œidœ:œAgent-oCAntœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-GCeTu{œfieldNameœ:œfirst_textœ,œidœ:œPrompt-GCeTuœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Agent-oCAnt", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-oCAntœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-GCeTu", - "targetHandle": "{œfieldNameœ: œfirst_textœ, œidœ: œPrompt-GCeTuœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Agent", - "id": "Agent-J7aBZ", - "name": "response", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "second_text", - "id": "Prompt-GCeTu", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Agent-J7aBZ{œdataTypeœ:œAgentœ,œidœ:œAgent-J7aBZœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-GCeTu{œfieldNameœ:œsecond_textœ,œidœ:œPrompt-GCeTuœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Agent-J7aBZ", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-J7aBZœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-GCeTu", - "targetHandle": "{œfieldNameœ: œsecond_textœ, œidœ: œPrompt-GCeTuœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-GCeTu", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "second_text", - "id": "Prompt-BghS1", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-GCeTu{œdataTypeœ:œPromptœ,œidœ:œPrompt-GCeTuœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Prompt-BghS1{œfieldNameœ:œsecond_textœ,œidœ:œPrompt-BghS1œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-GCeTu", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-GCeTuœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-BghS1", - "targetHandle": "{œfieldNameœ: œsecond_textœ, œidœ: œPrompt-BghS1œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-qozug", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "first_text", - "id": "Prompt-BghS1", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-qozug{œdataTypeœ:œChatInputœ,œidœ:œChatInput-qozugœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-BghS1{œfieldNameœ:œfirst_textœ,œidœ:œPrompt-BghS1œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-qozug", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-qozugœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-BghS1", - "targetHandle": "{œfieldNameœ: œfirst_textœ, œidœ: œPrompt-BghS1œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-BghS1", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "SambaNovaModel-8WRTL", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-BghS1{œdataTypeœ:œPromptœ,œidœ:œPrompt-BghS1œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-SambaNovaModel-8WRTL{œfieldNameœ:œinput_valueœ,œidœ:œSambaNovaModel-8WRTLœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-BghS1", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-BghS1œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "SambaNovaModel-8WRTL", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œSambaNovaModel-8WRTLœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "YfinanceComponent", - "id": "YfinanceComponent-XI4d2", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-oCAnt", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-YfinanceComponent-XI4d2{œdataTypeœ:œYfinanceComponentœ,œidœ:œYfinanceComponent-XI4d2œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-oCAnt{œfieldNameœ:œtoolsœ,œidœ:œAgent-oCAntœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "YfinanceComponent-XI4d2", - "sourceHandle": "{œdataTypeœ: œYfinanceComponentœ, œidœ: œYfinanceComponent-XI4d2œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-oCAnt", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-oCAntœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - } - ], - "nodes": [ - { - "data": { - "id": "ChatInput-qozug", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "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", - "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, - "template": { - "_type": "Component", - "background_color": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Background Color", - "dynamic": false, - "info": "The background color of the icon.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "background_color", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "chat_icon": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Icon", - "dynamic": false, - "info": "The icon of the message.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "chat_icon", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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 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 MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(display_name=\"Chat Message\", name=\"message\", method=\"message_response\"),\n ]\n\n async def message_response(self) -> Message:\n background_color = self.background_color\n text_color = self.text_color\n icon = self.chat_icon\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=self.files,\n properties={\n \"background_color\": background_color,\n \"text_color\": text_color,\n \"icon\": icon,\n },\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": [ - "txt", - "md", - "mdx", - "csv", - "json", - "yaml", - "yml", - "xml", - "html", - "htm", - "pdf", - "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, - "temp_file": true, - "title_case": false, - "trace_as_metadata": true, - "type": "file", - "value": "" - }, - "input_value": { - "_input_type": "MultilineInput", - "advanced": 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 - }, - "text_color": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Text Color", - "dynamic": false, - "info": "The text color of the name", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "text_color", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - } - }, - "tool_mode": false - }, - "selected_output": "message", - "showNode": false, - "type": "ChatInput" - }, - "dragging": false, - "id": "ChatInput-qozug", - "measured": { - "height": 48, - "width": 192 - }, - "position": { - "x": -777.5771293156841, - "y": 305.2723025086492 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "TavilySearchComponent-5hDm1", - "node": { - "base_classes": [ - "Data", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "**Tavily Search** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", - "display_name": "Tavily AI Search", - "documentation": "", - "edited": false, - "field_order": [ - "api_key", - "query", - "search_depth", - "topic", - "time_range", - "max_results", - "include_images", - "include_answer" - ], - "frozen": false, - "icon": "TavilyIcon", - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "group_outputs": false, - "hidden": false, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "Tavily API Key", - "dynamic": false, - "info": "Your Tavily API Key.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "TAVILY_API_KEY" - }, - "chunks_per_source": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Chunks Per Source", - "dynamic": false, - "info": "The number of content chunks to retrieve from each source (1-3). Only works with advanced search.", - "list": false, - "list_add_label": "Add More", - "name": "chunks_per_source", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 3 - }, - "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 httpx\nfrom loguru import logger\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import BoolInput, DropdownInput, IntInput, MessageTextInput, SecretStrInput\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.template.field.base import Output\n\n\nclass TavilySearchComponent(Component):\n display_name = \"Tavily Search API\"\n description = \"\"\"**Tavily Search** is a search engine optimized for LLMs and RAG, \\\n aimed at efficient, quick, and persistent search results.\"\"\"\n icon = \"TavilyIcon\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Tavily API Key\",\n required=True,\n info=\"Your Tavily API Key.\",\n ),\n MessageTextInput(\n name=\"query\",\n display_name=\"Search Query\",\n info=\"The search query you want to execute with Tavily.\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"search_depth\",\n display_name=\"Search Depth\",\n info=\"The depth of the search.\",\n options=[\"basic\", \"advanced\"],\n value=\"advanced\",\n advanced=True,\n ),\n IntInput(\n name=\"chunks_per_source\",\n display_name=\"Chunks Per Source\",\n info=(\"The number of content chunks to retrieve from each source (1-3). Only works with advanced search.\"),\n value=3,\n advanced=True,\n ),\n DropdownInput(\n name=\"topic\",\n display_name=\"Search Topic\",\n info=\"The category of the search.\",\n options=[\"general\", \"news\"],\n value=\"general\",\n advanced=True,\n ),\n IntInput(\n name=\"days\",\n display_name=\"Days\",\n info=\"Number of days back from current date to include. Only available with news topic.\",\n value=7,\n advanced=True,\n ),\n IntInput(\n name=\"max_results\",\n display_name=\"Max Results\",\n info=\"The maximum number of search results to return.\",\n value=5,\n advanced=True,\n ),\n BoolInput(\n name=\"include_answer\",\n display_name=\"Include Answer\",\n info=\"Include a short answer to original query.\",\n value=True,\n advanced=True,\n ),\n DropdownInput(\n name=\"time_range\",\n display_name=\"Time Range\",\n info=\"The time range back from the current date to filter results.\",\n options=[\"day\", \"week\", \"month\", \"year\"],\n value=None, # Default to None to make it optional\n advanced=True,\n ),\n BoolInput(\n name=\"include_images\",\n display_name=\"Include Images\",\n info=\"Include a list of query-related images in the response.\",\n value=True,\n advanced=True,\n ),\n MessageTextInput(\n name=\"include_domains\",\n display_name=\"Include Domains\",\n info=\"Comma-separated list of domains to include in the search results.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"exclude_domains\",\n display_name=\"Exclude Domains\",\n info=\"Comma-separated list of domains to exclude from the search results.\",\n advanced=True,\n ),\n BoolInput(\n name=\"include_raw_content\",\n display_name=\"Include Raw Content\",\n info=\"Include the cleaned and parsed HTML content of each search result.\",\n value=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def fetch_content(self) -> list[Data]:\n try:\n # Only process domains if they're provided\n include_domains = None\n exclude_domains = None\n\n if self.include_domains:\n include_domains = [domain.strip() for domain in self.include_domains.split(\",\") if domain.strip()]\n\n if self.exclude_domains:\n exclude_domains = [domain.strip() for domain in self.exclude_domains.split(\",\") if domain.strip()]\n\n url = \"https://api.tavily.com/search\"\n headers = {\n \"content-type\": \"application/json\",\n \"accept\": \"application/json\",\n }\n\n payload = {\n \"api_key\": self.api_key,\n \"query\": self.query,\n \"search_depth\": self.search_depth,\n \"topic\": self.topic,\n \"max_results\": self.max_results,\n \"include_images\": self.include_images,\n \"include_answer\": self.include_answer,\n \"include_raw_content\": self.include_raw_content,\n \"days\": self.days,\n \"time_range\": self.time_range,\n }\n\n # Only add domains to payload if they exist and have values\n if include_domains:\n payload[\"include_domains\"] = include_domains\n if exclude_domains:\n payload[\"exclude_domains\"] = exclude_domains\n\n # Add conditional parameters only if they should be included\n if self.search_depth == \"advanced\" and self.chunks_per_source:\n payload[\"chunks_per_source\"] = self.chunks_per_source\n\n if self.topic == \"news\" and self.days:\n payload[\"days\"] = int(self.days) # Ensure days is an integer\n\n # Add time_range if it's set\n if hasattr(self, \"time_range\") and self.time_range:\n payload[\"time_range\"] = self.time_range\n\n # Add timeout handling\n with httpx.Client(timeout=90.0) as client:\n response = client.post(url, json=payload, headers=headers)\n\n response.raise_for_status()\n search_results = response.json()\n\n data_results = []\n\n if self.include_answer and search_results.get(\"answer\"):\n data_results.append(Data(text=search_results[\"answer\"]))\n\n for result in search_results.get(\"results\", []):\n content = result.get(\"content\", \"\")\n result_data = {\n \"title\": result.get(\"title\"),\n \"url\": result.get(\"url\"),\n \"content\": content,\n \"score\": result.get(\"score\"),\n }\n if self.include_raw_content:\n result_data[\"raw_content\"] = result.get(\"raw_content\")\n\n data_results.append(Data(text=content, data=result_data))\n\n if self.include_images and search_results.get(\"images\"):\n data_results.append(Data(text=\"Images found\", data={\"images\": search_results[\"images\"]}))\n\n except httpx.TimeoutException:\n error_message = \"Request timed out (90s). Please try again or adjust parameters.\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.HTTPStatusError as exc:\n error_message = f\"HTTP error occurred: {exc.response.status_code} - {exc.response.text}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except httpx.RequestError as exc:\n error_message = f\"Request error occurred: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n except ValueError as exc:\n error_message = f\"Invalid response format: {exc}\"\n logger.error(error_message)\n return [Data(text=error_message, data={\"error\": error_message})]\n else:\n self.status = data_results\n return data_results\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" - }, - "days": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Days", - "dynamic": false, - "info": "Number of days back from current date to include. Only available with news topic.", - "list": false, - "list_add_label": "Add More", - "name": "days", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 7 - }, - "exclude_domains": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Exclude Domains", - "dynamic": false, - "info": "Comma-separated list of domains to exclude from the search results.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "exclude_domains", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "include_answer": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Include Answer", - "dynamic": false, - "info": "Include a short answer to original query.", - "list": false, - "list_add_label": "Add More", - "name": "include_answer", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "include_domains": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Include Domains", - "dynamic": false, - "info": "Comma-separated list of domains to include in the search results.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "include_domains", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "include_images": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Include Images", - "dynamic": false, - "info": "Include a list of query-related images in the response.", - "list": false, - "list_add_label": "Add More", - "name": "include_images", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "include_raw_content": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Include Raw Content", - "dynamic": false, - "info": "Include the cleaned and parsed HTML content of each search result.", - "list": false, - "list_add_label": "Add More", - "name": "include_raw_content", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_results": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Results", - "dynamic": false, - "info": "The maximum number of search results to return.", - "list": false, - "list_add_label": "Add More", - "name": "max_results", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "query": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Search Query", - "dynamic": false, - "info": "The search query you want to execute with Tavily.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "query", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "search_depth": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Search Depth", - "dynamic": false, - "info": "The depth of the search.", - "name": "search_depth", - "options": [ - "basic", - "advanced" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "advanced" - }, - "time_range": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Time Range", - "dynamic": false, - "info": "The time range back from the current date to filter results.", - "name": "time_range", - "options": [ - "day", - "week", - "month", - "year" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str" - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": { - "query": { - "default": "", - "description": "The search query you want to execute with Tavily.", - "title": "Query", - "type": "string" - } - }, - "description": "**Tavily Search** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", - "display_description": "**Tavily Search** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", - "display_name": "fetch_content_dataframe", - "name": "fetch_content_dataframe", - "readonly": false, - "status": true, - "tags": [ - "fetch_content_dataframe" - ] - } - ] - }, - "topic": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Search Topic", - "dynamic": false, - "info": "The category of the search.", - "name": "topic", - "options": [ - "general", - "news" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "general" - } - }, - "tool_mode": true - }, - "selected_output": "component_as_tool", - "showNode": true, - "type": "TavilySearchComponent" - }, - "dragging": false, - "id": "TavilySearchComponent-5hDm1", - "measured": { - "height": 316, - "width": 320 - }, - "position": { - "x": -682.4849400136196, - "y": 584.5279981500064 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "description": "Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", - "display_name": "Yahoo Finance", - "id": "YfinanceComponent-XI4d2", - "node": { - "base_classes": [ - "Data", - "DataFrame", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", - "display_name": "Yahoo Finance", - "documentation": "", - "edited": false, - "field_order": [ - "symbol", - "method", - "num_news" - ], - "frozen": false, - "icon": "trending-up", - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "group_outputs": false, - "hidden": false, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import ast\nimport pprint\nfrom enum import Enum\n\nimport yfinance as yf\nfrom langchain_core.tools import ToolException\nfrom loguru import logger\nfrom pydantic import BaseModel, Field\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import DropdownInput, IntInput, MessageTextInput\nfrom langflow.io import Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass YahooFinanceMethod(Enum):\n GET_INFO = \"get_info\"\n GET_NEWS = \"get_news\"\n GET_ACTIONS = \"get_actions\"\n GET_ANALYSIS = \"get_analysis\"\n GET_BALANCE_SHEET = \"get_balance_sheet\"\n GET_CALENDAR = \"get_calendar\"\n GET_CASHFLOW = \"get_cashflow\"\n GET_INSTITUTIONAL_HOLDERS = \"get_institutional_holders\"\n GET_RECOMMENDATIONS = \"get_recommendations\"\n GET_SUSTAINABILITY = \"get_sustainability\"\n GET_MAJOR_HOLDERS = \"get_major_holders\"\n GET_MUTUALFUND_HOLDERS = \"get_mutualfund_holders\"\n GET_INSIDER_PURCHASES = \"get_insider_purchases\"\n GET_INSIDER_TRANSACTIONS = \"get_insider_transactions\"\n GET_INSIDER_ROSTER_HOLDERS = \"get_insider_roster_holders\"\n GET_DIVIDENDS = \"get_dividends\"\n GET_CAPITAL_GAINS = \"get_capital_gains\"\n GET_SPLITS = \"get_splits\"\n GET_SHARES = \"get_shares\"\n GET_FAST_INFO = \"get_fast_info\"\n GET_SEC_FILINGS = \"get_sec_filings\"\n GET_RECOMMENDATIONS_SUMMARY = \"get_recommendations_summary\"\n GET_UPGRADES_DOWNGRADES = \"get_upgrades_downgrades\"\n GET_EARNINGS = \"get_earnings\"\n GET_INCOME_STMT = \"get_income_stmt\"\n\n\nclass YahooFinanceSchema(BaseModel):\n symbol: str = Field(..., description=\"The stock symbol to retrieve data for.\")\n method: YahooFinanceMethod = Field(YahooFinanceMethod.GET_INFO, description=\"The type of data to retrieve.\")\n num_news: int | None = Field(5, description=\"The number of news articles to retrieve.\")\n\n\nclass YfinanceComponent(Component):\n display_name = \"Yahoo Finance\"\n description = \"\"\"Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) \\\nto access financial data and market information from Yahoo Finance.\"\"\"\n icon = \"trending-up\"\n\n inputs = [\n MessageTextInput(\n name=\"symbol\",\n display_name=\"Stock Symbol\",\n info=\"The stock symbol to retrieve data for (e.g., AAPL, GOOG).\",\n tool_mode=True,\n ),\n DropdownInput(\n name=\"method\",\n display_name=\"Data Method\",\n info=\"The type of data to retrieve.\",\n options=list(YahooFinanceMethod),\n value=\"get_news\",\n ),\n IntInput(\n name=\"num_news\",\n display_name=\"Number of News\",\n info=\"The number of news articles to retrieve (only applicable for get_news).\",\n value=5,\n ),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def _fetch_yfinance_data(self, ticker: yf.Ticker, method: YahooFinanceMethod, num_news: int | None) -> str:\n try:\n if method == YahooFinanceMethod.GET_INFO:\n result = ticker.info\n elif method == YahooFinanceMethod.GET_NEWS:\n result = ticker.news[:num_news]\n else:\n result = getattr(ticker, method.value)()\n return pprint.pformat(result)\n except Exception as e:\n error_message = f\"Error retrieving data: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def fetch_content(self) -> list[Data]:\n try:\n return self._yahoo_finance_tool(\n self.symbol,\n YahooFinanceMethod(self.method),\n self.num_news,\n )\n except ToolException:\n raise\n except Exception as e:\n error_message = f\"Unexpected error: {e}\"\n logger.debug(error_message)\n self.status = error_message\n raise ToolException(error_message) from e\n\n def _yahoo_finance_tool(\n self,\n symbol: str,\n method: YahooFinanceMethod,\n num_news: int | None = 5,\n ) -> list[Data]:\n ticker = yf.Ticker(symbol)\n result = self._fetch_yfinance_data(ticker, method, num_news)\n\n if method == YahooFinanceMethod.GET_NEWS:\n data_list = [\n Data(text=f\"{article['title']}: {article['link']}\", data=article)\n for article in ast.literal_eval(result)\n ]\n else:\n data_list = [Data(text=result, data={\"result\": result})]\n\n return data_list\n\n def fetch_content_dataframe(self) -> DataFrame:\n data = self.fetch_content()\n return DataFrame(data)\n" - }, - "method": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Data Method", - "dynamic": false, - "info": "The type of data to retrieve.", - "name": "method", - "options": [ - "get_info", - "get_news", - "get_actions", - "get_analysis", - "get_balance_sheet", - "get_calendar", - "get_cashflow", - "get_institutional_holders", - "get_recommendations", - "get_sustainability", - "get_major_holders", - "get_mutualfund_holders", - "get_insider_purchases", - "get_insider_transactions", - "get_insider_roster_holders", - "get_dividends", - "get_capital_gains", - "get_splits", - "get_shares", - "get_fast_info", - "get_sec_filings", - "get_recommendations_summary", - "get_upgrades_downgrades", - "get_earnings", - "get_income_stmt" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "get_news" - }, - "num_news": { - "_input_type": "IntInput", - "advanced": false, - "display_name": "Number of News", - "dynamic": false, - "info": "The number of news articles to retrieve (only applicable for get_news).", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "num_news", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 3 - }, - "symbol": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Stock Symbol", - "dynamic": false, - "info": "The stock symbol to retrieve data for (e.g., AAPL, GOOG).", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "symbol", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": { - "symbol": { - "default": "", - "description": "The stock symbol to retrieve data for (e.g., AAPL, GOOG).", - "title": "Symbol", - "type": "string" - } - }, - "description": "Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", - "display_description": "Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", - "display_name": "fetch_content_dataframe", - "name": "fetch_content_dataframe", - "readonly": false, - "status": true, - "tags": [ - "fetch_content_dataframe" - ] - } - ] - } - }, - "tool_mode": true - }, - "selected_output": "component_as_tool", - "showNode": true, - "type": "YfinanceComponent" - }, - "dragging": false, - "id": "YfinanceComponent-XI4d2", - "measured": { - "height": 398, - "width": 320 - }, - "position": { - "x": -569.2623156750083, - "y": -297.11014493503006 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "ChatOutput-Cvbe8", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Display a chat message in the Playground.", - "display_name": "Chat Output", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "should_store_message", - "sender", - "sender_name", - "session_id", - "data_template", - "background_color", - "chat_icon", - "text_color" - ], - "frozen": false, - "icon": "MessagesSquare", - "legacy": false, - "lf_version": "1.4.3", - "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, - "template": { - "_type": "Component", - "background_color": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Background Color", - "dynamic": false, - "info": "The background color of the icon.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "background_color", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "chat_icon": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Icon", - "dynamic": false, - "info": "The icon of the message.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "chat_icon", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "clean_data": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Basic Clean Data", - "dynamic": false, - "info": "Whether to clean the data", - "list": false, - "list_add_label": "Add More", - "name": "clean_data", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from collections.abc import Generator\nfrom typing import Any\n\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 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 MessageTextInput(\n name=\"background_color\",\n display_name=\"Background Color\",\n info=\"The background color of the icon.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"chat_icon\",\n display_name=\"Icon\",\n info=\"The icon of the message.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"text_color\",\n display_name=\"Text Color\",\n info=\"The text color of the name\",\n advanced=True,\n ),\n BoolInput(\n name=\"clean_data\",\n display_name=\"Basic Clean Data\",\n value=True,\n info=\"Whether to clean the data\",\n advanced=True,\n ),\n ]\n outputs = [\n Output(\n display_name=\"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 background_color = self.background_color\n text_color = self.text_color\n if self.chat_icon:\n icon = self.chat_icon\n\n # Create or use existing Message object\n if isinstance(self.input_value, Message):\n message = self.input_value\n # Update message properties\n message.text = text\n else:\n message = Message(text=text)\n\n # Set message properties\n message.sender = self.sender\n message.sender_name = self.sender_name\n message.session_id = self.session_id\n message.flow_id = self.graph.flow_id if hasattr(self, \"graph\") else None\n message.properties.source = self._build_source(source_id, display_name, source)\n message.properties.icon = icon\n message.properties.background_color = background_color\n message.properties.text_color = text_color\n\n # Store message if needed\n if self.session_id and self.should_store_message:\n stored_message = await self.send_message(message)\n self.message.value = stored_message\n message = stored_message\n\n self.status = message\n return message\n\n def _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 return \"\\n\".join([safe_convert(item, clean_data=self.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": "MessageInput", - "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", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "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": "Machine" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Name of the sender.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "AI" - }, - "session_id": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Session ID", - "dynamic": false, - "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "session_id", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "should_store_message": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Store Messages", - "dynamic": false, - "info": "Store the message in the history.", - "list": false, - "list_add_label": "Add More", - "name": "should_store_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "text_color": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Text Color", - "dynamic": false, - "info": "The text color of the name", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "text_color", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - } - }, - "tool_mode": false - }, - "showNode": false, - "type": "ChatOutput" - }, - "dragging": false, - "id": "ChatOutput-Cvbe8", - "measured": { - "height": 48, - "width": 192 - }, - "position": { - "x": 1915.4342657794896, - "y": 441.2937993426264 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "URL-mbCdn", - "node": { - "base_classes": [ - "Data", - "DataFrame", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Fetch content from one or more web pages, following links recursively.", - "display_name": "URL", - "documentation": "", - "edited": false, - "field_order": [ - "urls", - "format", - "separator", - "clean_extra_whitespace" - ], - "frozen": false, - "icon": "layout-template", - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "group_outputs": false, - "hidden": null, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "autoset_encoding": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Autoset Encoding", - "dynamic": false, - "info": "If enabled, automatically sets the encoding of the request.", - "list": false, - "list_add_label": "Add More", - "name": "autoset_encoding", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "check_response_status": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Check Response Status", - "dynamic": false, - "info": "If enabled, checks the response status of the request.", - "list": false, - "list_add_label": "Add More", - "name": "check_response_status", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "import re\n\nimport requests\nfrom bs4 import BeautifulSoup\nfrom langchain_community.document_loaders import RecursiveUrlLoader\nfrom loguru import logger\n\nfrom langflow.custom import Component\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.helpers.data import safe_convert\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SliderInput, TableInput\nfrom langflow.schema import DataFrame, Message\nfrom langflow.services.deps import get_settings_service\n\n# Constants\nDEFAULT_TIMEOUT = 30\nDEFAULT_MAX_DEPTH = 1\nDEFAULT_FORMAT = \"Text\"\nURL_REGEX = re.compile(\n r\"^(https?:\\/\\/)?\" r\"(www\\.)?\" r\"([a-zA-Z0-9.-]+)\" r\"(\\.[a-zA-Z]{2,})?\" r\"(:\\d+)?\" r\"(\\/[^\\s]*)?$\",\n re.IGNORECASE,\n)\n\n\nclass URLComponent(Component):\n \"\"\"A component that loads and parses content from web pages recursively.\n\n This component allows fetching content from one or more URLs, with options to:\n - Control crawl depth\n - Prevent crawling outside the root domain\n - Use async loading for better performance\n - Extract either raw HTML or clean text\n - Configure request headers and timeouts\n \"\"\"\n\n display_name = \"URL\"\n description = \"Fetch content from one or more web pages, following links recursively.\"\n icon = \"layout-template\"\n name = \"URLComponent\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs to crawl recursively, by clicking the '+' button.\",\n is_list=True,\n tool_mode=True,\n placeholder=\"Enter a URL...\",\n list_add_label=\"Add URL\",\n input_types=[],\n ),\n SliderInput(\n name=\"max_depth\",\n display_name=\"Depth\",\n info=(\n \"Controls how many 'clicks' away from the initial page the crawler will go:\\n\"\n \"- depth 1: only the initial page\\n\"\n \"- depth 2: initial page + all pages linked directly from it\\n\"\n \"- depth 3: initial page + direct links + links found on those direct link pages\\n\"\n \"Note: This is about link traversal, not URL path depth.\"\n ),\n value=DEFAULT_MAX_DEPTH,\n range_spec=RangeSpec(min=1, max=5, step=1),\n required=False,\n min_label=\" \",\n max_label=\" \",\n min_label_icon=\"None\",\n max_label_icon=\"None\",\n # slider_input=True\n ),\n BoolInput(\n name=\"prevent_outside\",\n display_name=\"Prevent Outside\",\n info=(\n \"If enabled, only crawls URLs within the same domain as the root URL. \"\n \"This helps prevent the crawler from going to external websites.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"use_async\",\n display_name=\"Use Async\",\n info=(\n \"If enabled, uses asynchronous loading which can be significantly faster \"\n \"but might use more system resources.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n DropdownInput(\n name=\"format\",\n display_name=\"Output Format\",\n info=\"Output Format. Use 'Text' to extract the text from the HTML or 'HTML' for the raw HTML content.\",\n options=[\"Text\", \"HTML\"],\n value=DEFAULT_FORMAT,\n advanced=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout for the request in seconds.\",\n value=DEFAULT_TIMEOUT,\n required=False,\n advanced=True,\n ),\n TableInput(\n name=\"headers\",\n display_name=\"Headers\",\n info=\"The headers to send with the request\",\n table_schema=[\n {\n \"name\": \"key\",\n \"display_name\": \"Header\",\n \"type\": \"str\",\n \"description\": \"Header name\",\n },\n {\n \"name\": \"value\",\n \"display_name\": \"Value\",\n \"type\": \"str\",\n \"description\": \"Header value\",\n },\n ],\n value=[{\"key\": \"User-Agent\", \"value\": get_settings_service().settings.user_agent}],\n advanced=True,\n input_types=[\"DataFrame\"],\n ),\n BoolInput(\n name=\"filter_text_html\",\n display_name=\"Filter Text/HTML\",\n info=\"If enabled, filters out text/css content type from the results.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"continue_on_failure\",\n display_name=\"Continue on Failure\",\n info=\"If enabled, continues crawling even if some requests fail.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"check_response_status\",\n display_name=\"Check Response Status\",\n info=\"If enabled, checks the response status of the request.\",\n value=False,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"autoset_encoding\",\n display_name=\"Autoset Encoding\",\n info=\"If enabled, automatically sets the encoding of the request.\",\n value=True,\n required=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Result\", name=\"page_results\", method=\"fetch_content\"),\n Output(display_name=\"Raw Result\", name=\"raw_results\", method=\"as_message\"),\n ]\n\n @staticmethod\n def validate_url(url: str) -> bool:\n \"\"\"Validates if the given string matches URL pattern.\n\n Args:\n url: The URL string to validate\n\n Returns:\n bool: True if the URL is valid, False otherwise\n \"\"\"\n return bool(URL_REGEX.match(url))\n\n def ensure_url(self, url: str) -> str:\n \"\"\"Ensures the given string is a valid URL.\n\n Args:\n url: The URL string to validate and normalize\n\n Returns:\n str: The normalized URL\n\n Raises:\n ValueError: If the URL is invalid\n \"\"\"\n url = url.strip()\n if not url.startswith((\"http://\", \"https://\")):\n url = \"https://\" + url\n\n if not self.validate_url(url):\n msg = f\"Invalid URL: {url}\"\n raise ValueError(msg)\n\n return url\n\n def _create_loader(self, url: str) -> RecursiveUrlLoader:\n \"\"\"Creates a RecursiveUrlLoader instance with the configured settings.\n\n Args:\n url: The URL to load\n\n Returns:\n RecursiveUrlLoader: Configured loader instance\n \"\"\"\n headers_dict = {header[\"key\"]: header[\"value\"] for header in self.headers}\n extractor = (lambda x: x) if self.format == \"HTML\" else (lambda x: BeautifulSoup(x, \"lxml\").get_text())\n\n return RecursiveUrlLoader(\n url=url,\n max_depth=self.max_depth,\n prevent_outside=self.prevent_outside,\n use_async=self.use_async,\n extractor=extractor,\n timeout=self.timeout,\n headers=headers_dict,\n check_response_status=self.check_response_status,\n continue_on_failure=self.continue_on_failure,\n base_url=url, # Add base_url to ensure consistent domain crawling\n autoset_encoding=self.autoset_encoding, # Enable automatic encoding detection\n exclude_dirs=[], # Allow customization of excluded directories\n link_regex=None, # Allow customization of link filtering\n )\n\n def fetch_url_contents(self) -> list[dict]:\n \"\"\"Load documents from the configured URLs.\n\n Returns:\n List[Data]: List of Data objects containing the fetched content\n\n Raises:\n ValueError: If no valid URLs are provided or if there's an error loading documents\n \"\"\"\n try:\n urls = list({self.ensure_url(url) for url in self.urls if url.strip()})\n logger.info(f\"URLs: {urls}\")\n if not urls:\n msg = \"No valid URLs provided.\"\n raise ValueError(msg)\n\n all_docs = []\n for url in urls:\n logger.info(f\"Loading documents from {url}\")\n\n try:\n loader = self._create_loader(url)\n docs = loader.load()\n\n if not docs:\n logger.warning(f\"No documents found for {url}\")\n continue\n\n logger.info(f\"Found {len(docs)} documents from {url}\")\n all_docs.extend(docs)\n\n except requests.exceptions.RequestException as e:\n logger.exception(f\"Error loading documents from {url}: {e}\")\n continue\n\n if not all_docs:\n msg = \"No documents were successfully loaded from any URL\"\n raise ValueError(msg)\n\n # data = [Data(text=doc.page_content, **doc.metadata) for doc in all_docs]\n data = [\n {\n \"text\": safe_convert(doc.page_content, clean_data=True),\n \"url\": doc.metadata.get(\"source\", \"\"),\n \"title\": doc.metadata.get(\"title\", \"\"),\n \"description\": doc.metadata.get(\"description\", \"\"),\n \"content_type\": doc.metadata.get(\"content_type\", \"\"),\n \"language\": doc.metadata.get(\"language\", \"\"),\n }\n for doc in all_docs\n ]\n except Exception as e:\n error_msg = e.message if hasattr(e, \"message\") else e\n msg = f\"Error loading documents: {error_msg!s}\"\n logger.exception(msg)\n raise ValueError(msg) from e\n return data\n\n def fetch_content(self) -> DataFrame:\n \"\"\"Convert the documents to a DataFrame.\"\"\"\n return DataFrame(data=self.fetch_url_contents())\n\n def as_message(self) -> Message:\n \"\"\"Convert the documents to a Message.\"\"\"\n url_contents = self.fetch_url_contents()\n return Message(text=\"\\n\\n\".join([x[\"text\"] for x in url_contents]), data={\"data\": url_contents})\n" - }, - "continue_on_failure": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Continue on Failure", - "dynamic": false, - "info": "If enabled, continues crawling even if some requests fail.", - "list": false, - "list_add_label": "Add More", - "name": "continue_on_failure", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "filter_text_html": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Filter Text/HTML", - "dynamic": false, - "info": "If enabled, filters out text/css content type from the results.", - "list": false, - "list_add_label": "Add More", - "name": "filter_text_html", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "format": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Output Format", - "dynamic": false, - "info": "Output Format. Use 'Text' to extract the text from the HTML or 'HTML' for the raw HTML content.", - "name": "format", - "options": [ - "Text", - "HTML" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Text" - }, - "headers": { - "_input_type": "TableInput", - "advanced": true, - "display_name": "Headers", - "dynamic": false, - "info": "The headers to send with the request", - "input_types": [ - "DataFrame" - ], - "is_list": true, - "list_add_label": "Add More", - "name": "headers", - "placeholder": "", - "required": false, - "show": true, - "table_icon": "Table", - "table_schema": { - "columns": [ - { - "default": "None", - "description": "Header name", - "disable_edit": false, - "display_name": "Header", - "edit_mode": "popover", - "filterable": true, - "formatter": "text", - "hidden": false, - "name": "key", - "sortable": true, - "type": "str" - }, - { - "default": "None", - "description": "Header value", - "disable_edit": false, - "display_name": "Value", - "edit_mode": "popover", - "filterable": true, - "formatter": "text", - "hidden": false, - "name": "value", - "sortable": true, - "type": "str" - } - ] - }, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "trigger_icon": "Table", - "trigger_text": "Open table", - "type": "table", - "value": [ - { - "key": "User-Agent", - "value": "langflow" - } - ] - }, - "max_depth": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Depth", - "dynamic": false, - "info": "Controls how many 'clicks' away from the initial page the crawler will go:\n- depth 1: only the initial page\n- depth 2: initial page + all pages linked directly from it\n- depth 3: initial page + direct links + links found on those direct link pages\nNote: This is about link traversal, not URL path depth.", - "max_label": " ", - "max_label_icon": "None", - "min_label": " ", - "min_label_icon": "None", - "name": "max_depth", - "placeholder": "", - "range_spec": { - "max": 5, - "min": 1, - "step": 1, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 1 - }, - "prevent_outside": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Prevent Outside", - "dynamic": false, - "info": "If enabled, only crawls URLs within the same domain as the root URL. This helps prevent the crawler from going to external websites.", - "list": false, - "list_add_label": "Add More", - "name": "prevent_outside", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "Timeout for the request in seconds.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 30 - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": { - "urls": { - "default": "", - "description": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "Fetch content from one or more web pages, following links recursively.", - "display_description": "Fetch content from one or more web pages, following links recursively.", - "display_name": "fetch_content", - "name": "fetch_content", - "readonly": false, - "status": true, - "tags": [ - "fetch_content" - ] - }, - { - "args": { - "urls": { - "default": "", - "description": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "Fetch content from one or more web pages, following links recursively.", - "display_description": "Fetch content from one or more web pages, following links recursively.", - "display_name": "as_message", - "name": "as_message", - "readonly": false, - "status": true, - "tags": [ - "as_message" - ] - } - ] - }, - "urls": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "URLs", - "dynamic": false, - "info": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", - "input_types": [], - "list": true, - "list_add_label": "Add URL", - "load_from_db": false, - "name": "urls", - "placeholder": "Enter a URL...", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "use_async": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Use Async", - "dynamic": false, - "info": "If enabled, uses asynchronous loading which can be significantly faster but might use more system resources.", - "list": false, - "list_add_label": "Add More", - "name": "use_async", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": true - }, - "selected_output": "component_as_tool", - "showNode": true, - "type": "URL" - }, - "dragging": false, - "id": "URL-mbCdn", - "measured": { - "height": 290, - "width": 320 - }, - "position": { - "x": -572.0477930604186, - "y": -1020.4800468962654 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "note-yhn5a", - "node": { - "description": "# Financial Assistant Agents \n\nThe Financial Assistant Agent retrieves content and writes reports about financial queries.\n\n## Prerequisites\n\n* [Tavily AI Search key](https://docs.tavily.com/welcome)\n* [SambaNova API key](https://cloud.sambanova.ai/) \n\n## Quickstart\n\n1. In both **Agent** components and **SambaNova** component, add your SambaNova API key. \nIn the **Model Provider** field, select **Sambanova**, and select a model.\n3. In the **Tavily Search** component, add your **Tavily API key**.\n4. Click the **Playground** and ask `Why did Nvidia stock drop in January?`", - "display_name": "", - "documentation": "", - "template": { - "backgroundColor": "amber" - } - }, - "type": "note" - }, - "dragging": false, - "height": 630, - "id": "note-yhn5a", - "measured": { - "height": 630, - "width": 478 - }, - "position": { - "x": -1119.9423274254439, - "y": -433.35853649245854 - }, - "resizing": false, - "selected": false, - "type": "noteNode", - "width": 478 - }, - { - "data": { - "id": "SambaNovaModel-8WRTL", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Generate text using Sambanova LLMs.", - "display_name": "SambaNova", - "documentation": "https://cloud.sambanova.ai/", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "base_url", - "model_name", - "api_key", - "max_tokens", - "top_p", - "temperature" - ], - "frozen": false, - "icon": "SambaNova", - "legacy": false, - "lf_version": "1.4.3", - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "Sambanova API Key", - "dynamic": false, - "info": "The Sambanova API Key to use for the Sambanova model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "SAMBANOVA_API_KEY" - }, - "base_url": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "SambaNova Cloud Base Url", - "dynamic": false, - "info": "The base URL of the Sambanova Cloud API. Defaults to https://api.sambanova.ai/v1/chat/completions. You can change this to use other urls like Sambastudio", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "base_url", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_sambanova import ChatSambaNovaCloud\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.sambanova_constants import SAMBANOVA_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.io import DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\n\n\nclass SambaNovaComponent(LCModelComponent):\n display_name = \"SambaNova\"\n description = \"Generate text using Sambanova LLMs.\"\n documentation = \"https://cloud.sambanova.ai/\"\n icon = \"SambaNova\"\n name = \"SambaNovaModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n StrInput(\n name=\"base_url\",\n display_name=\"SambaNova Cloud Base Url\",\n advanced=True,\n info=\"The base URL of the Sambanova Cloud API. \"\n \"Defaults to https://api.sambanova.ai/v1/chat/completions. \"\n \"You can change this to use other urls like Sambastudio\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=SAMBANOVA_MODEL_NAMES,\n value=SAMBANOVA_MODEL_NAMES[0],\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"Sambanova API Key\",\n info=\"The Sambanova API Key to use for the Sambanova model.\",\n advanced=False,\n value=\"SAMBANOVA_API_KEY\",\n required=True,\n ),\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n value=2048,\n info=\"The maximum number of tokens to generate.\",\n ),\n SliderInput(\n name=\"top_p\",\n display_name=\"top_p\",\n advanced=True,\n value=1.0,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n info=\"Model top_p\",\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=2, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n sambanova_url = self.base_url\n sambanova_api_key = self.api_key\n model_name = self.model_name\n max_tokens = self.max_tokens\n top_p = self.top_p\n temperature = self.temperature\n\n api_key = SecretStr(sambanova_api_key).get_secret_value() if sambanova_api_key else None\n\n return ChatSambaNovaCloud(\n model=model_name,\n max_tokens=max_tokens or 1024,\n temperature=temperature or 0.07,\n top_p=top_p,\n sambanova_url=sambanova_url,\n sambanova_api_key=api_key,\n )\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 2048 - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "Meta-Llama-3.3-70B-Instruct", - "Meta-Llama-3.1-8B-Instruct", - "Meta-Llama-3.1-70B-Instruct", - "Meta-Llama-3.1-405B-Instruct", - "DeepSeek-R1-Distill-Llama-70B", - "DeepSeek-R1", - "Meta-Llama-3.2-1B-Instruct", - "Meta-Llama-3.2-3B-Instruct", - "Llama-3.2-11B-Vision-Instruct", - "Llama-3.2-90B-Vision-Instruct", - "Qwen2.5-Coder-32B-Instruct", - "Qwen2.5-72B-Instruct", - "QwQ-32B-Preview", - "Qwen2-Audio-7B-Instruct" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Meta-Llama-3.1-405B-Instruct" - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a helpful assistant who writes financial reports based on user query.\nYou will get a financial and research summary.\nPlease write a financial report or answer using the provided context and input text only.\n{input}\nYour answer should be in the same language as the initial query." - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 2, - "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 - }, - "top_p": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "top_p", - "dynamic": false, - "info": "Model top_p", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "top_p", - "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": 1 - } - }, - "tool_mode": false - }, - "selected_output": "text_output", - "showNode": true, - "type": "SambaNovaModel" - }, - "dragging": false, - "id": "SambaNovaModel-8WRTL", - "measured": { - "height": 450, - "width": 320 - }, - "position": { - "x": 1198.0223558351377, - "y": 154.90656214876276 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Agent-J7aBZ", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "category": "agents", - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "key": "Agent", - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "options": null, - "required_inputs": null, - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 1.1732828199964098e-19, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Anthropic", - "Google Generative AI", - "Groq", - "OpenAI", - "Custom" - ], - "options_metadata": [ - { - "icon": "Amazon" - }, - { - "icon": "Anthropic" - }, - { - "icon": "Azure" - }, - { - "icon": "GoogleGenerativeAI" - }, - { - "icon": "Groq" - }, - { - "icon": "NVIDIA" - }, - { - "icon": "OpenAI" - }, - { - "icon": "SambaNova" - }, - { - "icon": "brain" - } - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "SambaNova" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "SambaNova API Key", - "dynamic": false, - "info": "The SambaNova API Key to use for the SambaNova model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "real_time_refresh": true, - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "SAMBANOVA_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 langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "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": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 2048 - }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "display_name": "Mode", - "dynamic": false, - "info": "Operation mode: Store messages or Retrieve messages.", - "input_types": [], - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "input_types": [], - "name": "model_name", - "options": [ - "Meta-Llama-3.3-70B-Instruct", - "Meta-Llama-3.1-8B-Instruct", - "Meta-Llama-3.1-70B-Instruct", - "Meta-Llama-3.1-405B-Instruct", - "DeepSeek-R1-Distill-Llama-70B", - "DeepSeek-R1", - "Meta-Llama-3.2-1B-Instruct", - "Meta-Llama-3.2-3B-Instruct", - "Llama-3.2-11B-Vision-Instruct", - "Llama-3.2-90B-Vision-Instruct", - "Qwen2.5-Coder-32B-Instruct", - "Qwen2.5-72B-Instruct", - "QwQ-32B-Preview", - "Qwen2-Audio-7B-Instruct" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": false, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Meta-Llama-3.3-70B-Instruct" - }, - "n_messages": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Number of Messages", - "dynamic": false, - "info": "Number of messages to retrieve.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "n_messages", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "input_types": [], - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "input_types": [ - "Message" - ], - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "options_metadata": [], - "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, - "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": "" - }, - "sender_type": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender Type", - "dynamic": false, - "info": "Filter by sender type.", - "input_types": [], - "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, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "copy_field": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a research agent, expert in web research, you must provide insights given the user question \n\n{input}\n\nThink step by step\nDo not call a tool if the input depends on another tool output that you do not have yet.\nDo not try to answer until you get all the tools output, if you do not have an answer yet, you can continue calling tools until you do.\nYour answer should be in the same language as the initial query.\nensure the tool calls are proper parsable json " - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "input_types": [], - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 2, - "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 - }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "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}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "list_add_label": "Add More", - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "showNode": true, - "type": "Agent" - }, - "dragging": false, - "id": "Agent-J7aBZ", - "measured": { - "height": 593, - "width": 320 - }, - "position": { - "x": -114.7705455447527, - "y": 395.9726937371793 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Agent-oCAnt", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "category": "agents", - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "key": "Agent", - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "options": null, - "required_inputs": null, - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 5.283996070936036e-7, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Anthropic", - "Google Generative AI", - "Groq", - "OpenAI", - "Custom" - ], - "options_metadata": [ - { - "icon": "Amazon" - }, - { - "icon": "Anthropic" - }, - { - "icon": "Azure" - }, - { - "icon": "GoogleGenerativeAI" - }, - { - "icon": "Groq" - }, - { - "icon": "NVIDIA" - }, - { - "icon": "OpenAI" - }, - { - "icon": "SambaNova" - }, - { - "icon": "brain" - } - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "SambaNova" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "Sambanova API Key", - "dynamic": false, - "info": "The SambaNova API Key to use for the SambaNova model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "real_time_refresh": true, - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "SAMBANOVA_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 langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "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": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 2048 - }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "display_name": "Mode", - "dynamic": false, - "info": "Operation mode: Store messages or Retrieve messages.", - "input_types": [], - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "input_types": [], - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": false, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "Meta-Llama-3.3-70B-Instruct" - }, - "n_messages": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Number of Messages", - "dynamic": false, - "info": "Number of messages to retrieve.", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "n_messages", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "input_types": [], - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "input_types": [ - "Message" - ], - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "options_metadata": [], - "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, - "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": "" - }, - "sender_type": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender Type", - "dynamic": false, - "info": "Filter by sender type.", - "input_types": [], - "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, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "copy_field": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a financial agent, \n\nYou are a helpful assistant, and you have access to several tools\n\nYou must provide insights given the user question, you can get links to the latest news, and you must open each link and research relevant information\n\n{input}\n\nThink step by step\nDo not call a tool if the input depends on another tool output you do not yet have.\nDo not try to answer until you get all the tools' output. If you do not have an answer yet, you can continue calling tools until you do.\nYour answer should be in the same language as the initial query.\nensure the tool calls are proper parsable json \nreturn the URLs used to create your response in the final answer" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "input_types": [], - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 2, - "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 - }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "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}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "list_add_label": "Add More", - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "input_types": [], - "list": false, - "list_add_label": "Add More", - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "showNode": true, - "type": "Agent" - }, - "dragging": false, - "id": "Agent-oCAnt", - "measured": { - "height": 593, - "width": 320 - }, - "position": { - "x": -77.82588111053366, - "y": -413.29696550729983 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Prompt-GCeTu", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": { - "template": [ - "first_text", - "second_text" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "edited": false, - "error": null, - "field_order": [ - "template", - "tool_placeholder" - ], - "frozen": false, - "full_path": null, - "icon": "braces", - "is_composition": null, - "is_input": null, - "is_output": null, - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "name": "", - "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, - "priority": null, - "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.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" - }, - "first_text": { - "advanced": false, - "display_name": "first_text", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "first_text", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "second_text": { - "advanced": false, - "display_name": "second_text", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "second_text", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "template": { - "_input_type": "PromptInput", - "advanced": false, - "display_name": "Template", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "prompt", - "value": "{first_text} \\n\\n\n{second_text}" - }, - "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, - "list_add_label": "Add More", - "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", - "showNode": true, - "type": "Prompt" - }, - "dragging": false, - "id": "Prompt-GCeTu", - "measured": { - "height": 386, - "width": 320 - }, - "position": { - "x": 363.96874256661516, - "y": 420.69943255589567 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Prompt-BghS1", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": { - "template": [ - "first_text", - "second_text" - ] - }, - "description": "Create a prompt template with dynamic variables.", - "display_name": "Prompt", - "documentation": "", - "edited": false, - "error": null, - "field_order": [ - "template", - "tool_placeholder" - ], - "frozen": false, - "full_path": null, - "icon": "braces", - "is_composition": null, - "is_input": null, - "is_output": null, - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "name": "", - "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, - "priority": null, - "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.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" - }, - "first_text": { - "advanced": false, - "display_name": "first_text", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "first_text", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "second_text": { - "advanced": false, - "display_name": "second_text", - "dynamic": false, - "field_type": "str", - "fileTypes": [], - "file_path": "", - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "second_text", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "template": { - "_input_type": "PromptInput", - "advanced": false, - "display_name": "Template", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "template", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "prompt", - "value": "{first_text} \\n\\n\n{second_text}" - }, - "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, - "list_add_label": "Add More", - "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", - "showNode": true, - "type": "Prompt" - }, - "dragging": false, - "id": "Prompt-BghS1", - "measured": { - "height": 386, - "width": 320 - }, - "position": { - "x": 767.2407006972445, - "y": 115.92884832779234 - }, - "selected": false, - "type": "genericNode" - } - ], - "viewport": { - "x": 443.41452386254014, - "y": 287.7203359909025, - "zoom": 0.3828602258274036 - } - }, - "description": "Financial assistant chatbot that uses specialized agents to research for financial information", - "endpoint_name": null, - "id": "45fad7d2-2a24-4049-ad1b-6d800f5cc4c6", - "is_component": false, - "last_tested_version": "1.4.3", - "name": "Financial Agent", - "tags": [ - "assistants", - "agents", - "q-a", - "web-scraping", - "sambanova" - ] -} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json index 6031bf62f..34caedadf 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "TextInput", - "id": "TextInput-vLxDr", + "id": "TextInput-v6xVK", "name": "text", "output_types": [ "Message" @@ -15,7 +15,7 @@ }, "targetHandle": { "fieldName": "guidelines", - "id": "Prompt-R71s9", + "id": "Prompt-6WdZA", "inputTypes": [ "Message", "Text" @@ -23,97 +23,12 @@ "type": "str" } }, - "id": "reactflow__edge-TextInput-vLxDr{œdataTypeœ:œTextInputœ,œidœ:œTextInput-vLxDrœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-R71s9{œfieldNameœ:œguidelinesœ,œidœ:œPrompt-R71s9œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-TextInput-v6xVK{œdataTypeœ:œTextInputœ,œidœ:œTextInput-v6xVKœ,œnameœ:œtextœ,œoutput_typesœ:[œMessageœ]}-Prompt-6WdZA{œfieldNameœ:œguidelinesœ,œidœ:œPrompt-6WdZAœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "TextInput-vLxDr", - "sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-vLxDrœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-R71s9", - "targetHandle": "{œfieldNameœ: œguidelinesœ, œidœ: œPrompt-R71s9œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-tPgYp", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-jKpnA", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-tPgYp{œdataTypeœ:œChatInputœ,œidœ:œChatInput-tPgYpœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-jKpnA{œfieldNameœ:œinput_valueœ,œidœ:œAgent-jKpnAœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-tPgYp", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-tPgYpœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-jKpnA", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-jKpnAœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Agent", - "id": "Agent-jKpnA", - "name": "response", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "context", - "id": "Prompt-R71s9", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Agent-jKpnA{œdataTypeœ:œAgentœ,œidœ:œAgent-jKpnAœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-R71s9{œfieldNameœ:œcontextœ,œidœ:œPrompt-R71s9œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Agent-jKpnA", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-jKpnAœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-R71s9", - "targetHandle": "{œfieldNameœ: œcontextœ, œidœ: œPrompt-R71s9œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "TavilySearchComponent", - "id": "TavilySearchComponent-HW6b0", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-jKpnA", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-TavilySearchComponent-HW6b0{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-HW6b0œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-jKpnA{œfieldNameœ:œtoolsœ,œidœ:œAgent-jKpnAœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "TavilySearchComponent-HW6b0", - "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-HW6b0œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-jKpnA", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-jKpnAœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "TextInput-v6xVK", + "sourceHandle": "{œdataTypeœ: œTextInputœ, œidœ: œTextInput-v6xVKœ, œnameœ: œtextœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-6WdZA", + "targetHandle": "{œfieldNameœ: œguidelinesœ, œidœ: œPrompt-6WdZAœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -121,7 +36,7 @@ "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-R71s9", + "id": "Prompt-nh8wW", "name": "prompt", "output_types": [ "Message" @@ -129,150 +44,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "OpenAIModel-dqLbl", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-R71s9{œdataTypeœ:œPromptœ,œidœ:œPrompt-R71s9œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-dqLbl{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-dqLblœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-R71s9", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-R71s9œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-dqLbl", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-dqLblœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-dqLbl", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "post", - "id": "Prompt-LCAlG", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-dqLbl{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-dqLblœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-LCAlG{œfieldNameœ:œpostœ,œidœ:œPrompt-LCAlGœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "selected": false, - "source": "OpenAIModel-dqLbl", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-dqLblœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-LCAlG", - "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-LCAlGœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-dqLbl", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "post", - "id": "Prompt-ZA2H7", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-dqLbl{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-dqLblœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-ZA2H7{œfieldNameœ:œpostœ,œidœ:œPrompt-ZA2H7œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "selected": false, - "source": "OpenAIModel-dqLbl", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-dqLblœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-ZA2H7", - "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-ZA2H7œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-LCAlG", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-7yVxU", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-LCAlG{œdataTypeœ:œPromptœ,œidœ:œPrompt-LCAlGœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-7yVxU{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-7yVxUœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-LCAlG", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-LCAlGœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-7yVxU", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-7yVxUœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-7yVxU", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "image_description", - "id": "Prompt-ZA2H7", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-7yVxU{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-7yVxUœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-ZA2H7{œfieldNameœ:œimage_descriptionœ,œidœ:œPrompt-ZA2H7œ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "selected": false, - "source": "OpenAIModel-7yVxU", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-7yVxUœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-ZA2H7", - "targetHandle": "{œfieldNameœ: œimage_descriptionœ, œidœ: œPrompt-ZA2H7œ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-ZA2H7", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-u37IQ", + "id": "ChatOutput-ICs65", "inputTypes": [ "Data", "DataFrame", @@ -281,18 +53,206 @@ "type": "str" } }, - "id": "reactflow__edge-Prompt-ZA2H7{œdataTypeœ:œPromptœ,œidœ:œPrompt-ZA2H7œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-u37IQ{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-u37IQœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Prompt-nh8wW{œdataTypeœ:œPromptœ,œidœ:œPrompt-nh8wWœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-ICs65{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-ICs65œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-ZA2H7", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-ZA2H7œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-u37IQ", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-u37IQœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-nh8wW", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-nh8wWœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-ICs65", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-ICs65œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-Gd97g", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-kSedw", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__ChatInput-Gd97g{œdataTypeœ:œChatInputœ,œidœ:œChatInput-Gd97gœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-kSedw{œfieldNameœ:œinput_valueœ,œidœ:œAgent-kSedwœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-Gd97g", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-Gd97gœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-kSedw", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-kSedwœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "TavilySearchComponent", + "id": "TavilySearchComponent-jX5Zu", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-kSedw", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__TavilySearchComponent-jX5Zu{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-jX5Zuœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-kSedw{œfieldNameœ:œtoolsœ,œidœ:œAgent-kSedwœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "selected": false, + "source": "TavilySearchComponent-jX5Zu", + "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-jX5Zuœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-kSedw", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-kSedwœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-6WdZA", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "LanguageModelComponent-Wd1th", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Prompt-6WdZA{œdataTypeœ:œPromptœ,œidœ:œPrompt-6WdZAœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-Wd1th{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-Wd1thœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Prompt-6WdZA", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-6WdZAœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-Wd1th", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-Wd1thœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-Wd1th", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "post", + "id": "Prompt-nh8wW", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "xy-edge__LanguageModelComponent-Wd1th{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-Wd1thœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-nh8wW{œfieldNameœ:œpostœ,œidœ:œPrompt-nh8wWœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "LanguageModelComponent-Wd1th", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-Wd1thœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-nh8wW", + "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-nh8wWœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-Wd1th", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "post", + "id": "Prompt-0fgLG", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "xy-edge__LanguageModelComponent-Wd1th{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-Wd1thœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-0fgLG{œfieldNameœ:œpostœ,œidœ:œPrompt-0fgLGœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "LanguageModelComponent-Wd1th", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-Wd1thœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-0fgLG", + "targetHandle": "{œfieldNameœ: œpostœ, œidœ: œPrompt-0fgLGœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-0fgLG", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "LanguageModelComponent-gDIcu", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Prompt-0fgLG{œdataTypeœ:œPromptœ,œidœ:œPrompt-0fgLGœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-gDIcu{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-gDIcuœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-0fgLG", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-0fgLGœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-gDIcu", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-gDIcuœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-gDIcu", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "image_description", + "id": "Prompt-nh8wW", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "xy-edge__LanguageModelComponent-gDIcu{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-gDIcuœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-nh8wW{œfieldNameœ:œimage_descriptionœ,œidœ:œPrompt-nh8wWœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "LanguageModelComponent-gDIcu", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-gDIcuœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-nh8wW", + "targetHandle": "{œfieldNameœ: œimage_descriptionœ, œidœ: œPrompt-nh8wWœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-tPgYp", + "id": "ChatInput-Gd97g", "node": { "base_classes": [ "Message" @@ -569,7 +529,7 @@ }, "dragging": false, "height": 234, - "id": "ChatInput-tPgYp", + "id": "ChatInput-Gd97g", "measured": { "height": 234, "width": 320 @@ -590,7 +550,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-R71s9", + "id": "Prompt-6WdZA", "node": { "base_classes": [ "Message" @@ -747,7 +707,7 @@ }, "dragging": false, "height": 433, - "id": "Prompt-R71s9", + "id": "Prompt-6WdZA", "measured": { "height": 433, "width": 320 @@ -766,7 +726,7 @@ }, { "data": { - "id": "TextInput-vLxDr", + "id": "TextInput-v6xVK", "node": { "base_classes": [ "Message" @@ -853,7 +813,7 @@ }, "dragging": false, "height": 234, - "id": "TextInput-vLxDr", + "id": "TextInput-v6xVK", "measured": { "height": 234, "width": 320 @@ -874,7 +834,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-LCAlG", + "id": "Prompt-0fgLG", "node": { "base_classes": [ "Message" @@ -1007,7 +967,7 @@ }, "dragging": false, "height": 347, - "id": "Prompt-LCAlG", + "id": "Prompt-0fgLG", "measured": { "height": 347, "width": 320 @@ -1028,7 +988,7 @@ "data": { "description": "Display a chat message in the Playground.", "display_name": "Chat Output", - "id": "ChatOutput-u37IQ", + "id": "ChatOutput-ICs65", "node": { "base_classes": [ "Message" @@ -1310,7 +1270,7 @@ }, "dragging": false, "height": 234, - "id": "ChatOutput-u37IQ", + "id": "ChatOutput-ICs65", "measured": { "height": 234, "width": 320 @@ -1327,699 +1287,11 @@ "type": "genericNode", "width": 320 }, - { - "data": { - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "id": "Agent-jKpnA", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "output_schema", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "output_parser", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "metadata": {}, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Anthropic", - "Google Generative AI", - "Groq", - "OpenAI", - "Custom" - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "OPENAI_API_KEY" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "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 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a helpful AI assistant. Use the following information from a web search to answer the user's question. If the search results don't contain relevant information, say so and offer to help with something else.\n\n{input}" - }, - "temperature": { - "_input_type": "FloatInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "list": false, - "name": "temperature", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "float", - "value": 0.1 - }, - "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}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "type": "Agent" - }, - "dragging": false, - "height": 650, - "id": "Agent-jKpnA", - "measured": { - "height": 650, - "width": 320 - }, - "position": { - "x": 5665.465212822881, - "y": 2760.0819124193113 - }, - "positionAbsolute": { - "x": 5665.465212822881, - "y": 2760.0819124193113 - }, - "selected": false, - "type": "genericNode", - "width": 320 - }, { "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-ZA2H7", + "id": "Prompt-nh8wW", "node": { "base_classes": [ "Message" @@ -2176,7 +1448,7 @@ }, "dragging": false, "height": 433, - "id": "Prompt-ZA2H7", + "id": "Prompt-nh8wW", "measured": { "height": 433, "width": 320 @@ -2195,7 +1467,7 @@ }, { "data": { - "id": "note-n88Sx", + "id": "note-dqmDG", "node": { "description": "# Instagram Copywriter \n\nWelcome to the Instagram Copywriter! This flow helps you create compelling Instagram posts with AI-generated content and image prompts.\n\n## Instructions\n1. Enter Your Topic\n - In the Chat Input, enter a brief description of the topic you want to post about.\n - Example: \"Create a post about meditation and its benefits\"\n\n2. Review the Generated Content\n - The flow will use AI to research your topic and generate a formatted Instagram post.\n - The post will include an opening line, main content, emojis, a call-to-action, and hashtags.\n\n3. Check the Image Prompt\n - The flow will also generate a detailed image prompt based on your post content.\n - This prompt can be used with image generation tools to create a matching visual.\n\n4. Copy the Final Output\n - The Chat Output will display the complete Instagram post text followed by the image generation prompt.\n - Copy this output to use in your Instagram content creation process.\n\n5. Refine if Needed\n - If you're not satisfied with the result, you can adjust the input or modify the OpenAI model settings for different outputs.\n\nRemember: Keep your initial topic input clear and concise for best results! 🎨✨", "display_name": "", @@ -2208,10 +1480,10 @@ }, "dragging": false, "height": 648, - "id": "note-n88Sx", + "id": "note-dqmDG", "measured": { "height": 648, - "width": 555 + "width": 554 }, "position": { "x": 4492.051129290571, @@ -2232,7 +1504,7 @@ }, { "data": { - "id": "note-6p3jo", + "id": "note-Lab5F", "node": { "description": "**Text Input (Guidelines Prompt)**\n - NOTE: \"Contains Instagram post formatting rules. Don't modify this component as it maintains format consistency.\"\n - Maintains fixed guidelines for:\n * Opening structure\n * Main content\n * Emoji usage\n * Call to Action (CTA)\n * Hashtags\n\n4. **First Prompt + OpenAI Sequence**\n - NOTE: \"Generates initial post content following Instagram guidelines\"\n - Settings:\n * Temperature: 0.7 (good balance between creativity and consistency)\n * Input: Receives research context\n * Output: Generates formatted post text\n\n", "display_name": "", @@ -2245,10 +1517,10 @@ }, "dragging": false, "height": 325, - "id": "note-6p3jo", + "id": "note-Lab5F", "measured": { "height": 325, - "width": 326 + "width": 325 }, "position": { "x": 5666.120349284508, @@ -2265,7 +1537,7 @@ }, { "data": { - "id": "note-izkhS", + "id": "note-iyMYI", "node": { "description": "**Second Prompt + OpenAI Sequence**\n - NOTE: \"Transforms the generated post into a prompt for image generation\"\n - Settings:\n * Temperature: 0.7\n * Input: Receives generated post\n * Output: Creates detailed description for image generation\n\n", "display_name": "", @@ -2278,10 +1550,10 @@ }, "dragging": false, "height": 325, - "id": "note-izkhS", + "id": "note-iyMYI", "measured": { "height": 325, - "width": 326 + "width": 325 }, "position": { "x": 6822.008614819107, @@ -2297,7 +1569,7 @@ }, { "data": { - "id": "note-cvuhQ", + "id": "note-ZnWF3", "node": { "description": "**Final Prompt**\n - NOTE: \"Combines Instagram post with image prompt in a final format\"\n - Structure:\n * First part: Complete Instagram post\n * Second part: Image generation prompt\n * Separator: Uses \"**Prompt:**\" to divide sections\n\n7. **Chat Output (Final Output)**\n - NOTE: \"Presents the combined final result that can be copied and used directly\"\n\nGENERAL USAGE TIPS:\n- Keep initial inputs clear and specific\n- Don't modify pre-defined Instagram guidelines\n- If style adjustments are needed, only modify the OpenAI models' temperature\n- Verify all connections are correct before running\n- Final result will always have two parts: post + image prompt\n\nFLOW CONSIDERATIONS:\n- All tools connect only to the Tool Calling Agent\n- The flow is unidirectional (no loops)\n- Each prompt template maintains specific formatting\n- Temperatures are set for optimal creativity/consistency balance\n\nTROUBLESHOOTING NOTES:\n- If output is too creative: Lower temperature", "display_name": "", @@ -2310,10 +1582,10 @@ }, "dragging": false, "height": 325, - "id": "note-cvuhQ", + "id": "note-ZnWF3", "measured": { "height": 325, - "width": 326 + "width": 325 }, "position": { "x": 7614.641944112834, @@ -2323,13 +1595,13 @@ "x": 7606.419013912975, "y": 3612.8149429707646 }, - "selected": true, + "selected": false, "type": "noteNode", "width": 325 }, { "data": { - "id": "note-BqKn1", + "id": "note-nZvRa", "node": { "description": "# 🔑 Tavily AI Search Needs API Key\n\nYou can get 1000 searches/month free [here](https://tavily.com/) ", "display_name": "", @@ -2342,10 +1614,10 @@ }, "dragging": false, "height": 325, - "id": "note-BqKn1", + "id": "note-nZvRa", "measured": { "height": 325, - "width": 326 + "width": 325 }, "position": { "x": 5174.678177457385, @@ -2361,7 +1633,7 @@ }, { "data": { - "id": "TavilySearchComponent-HW6b0", + "id": "TavilySearchComponent-jX5Zu", "node": { "base_classes": [ "Data", @@ -2395,6 +1667,7 @@ "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": null, "method": "to_toolkit", "name": "component_as_tool", @@ -2418,7 +1691,7 @@ "dynamic": false, "info": "Your Tavily API Key.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -2426,7 +1699,7 @@ "show": true, "title_case": false, "type": "str", - "value": "TAVILY_API_KEY" + "value": "" }, "chunks_per_source": { "_input_type": "IntInput", @@ -2671,11 +1944,11 @@ "type": "str" }, "tools_metadata": { - "_input_type": "TableInput", + "_input_type": "ToolsInput", "advanced": false, - "display_name": "Edit tools", + "display_name": "Actions", "dynamic": false, - "info": "", + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", "is_list": true, "list_add_label": "Add More", "name": "tools_metadata", @@ -2683,100 +1956,28 @@ "real_time_refresh": true, "required": false, "show": true, - "table_icon": "Hammer", - "table_options": { - "block_add": true, - "block_delete": true, - "block_edit": true, - "block_filter": true, - "block_hide": true, - "block_select": true, - "block_sort": true, - "description": "Modify tool names and descriptions to help agents understand when to use each tool.", - "field_parsers": { - "commands": "commands", - "name": [ - "snake_case", - "no_blank" - ] - }, - "hide_options": true - }, - "table_schema": { - "columns": [ - { - "default": "None", - "description": "Specify the name of the tool.", - "disable_edit": false, - "display_name": "Tool Name", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "name", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "Describe the purpose of the tool.", - "disable_edit": false, - "display_name": "Tool Description", - "edit_mode": "popover", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "description", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "The default identifiers for the tools and cannot be changed.", - "disable_edit": true, - "display_name": "Tool Identifiers", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": true, - "name": "tags", - "sortable": false, - "type": "str" - }, - { - "default": true, - "description": "Indicates whether the tool is currently active. Set to True to activate this tool.", - "disable_edit": false, - "display_name": "Enable", - "edit_mode": "popover", - "filterable": true, - "formatter": "boolean", - "hidden": false, - "name": "status", - "sortable": true, - "type": "boolean" - } - ] - }, "title_case": false, "tool_mode": false, "trace_as_metadata": true, - "trigger_icon": "Hammer", - "trigger_text": "", - "type": "table", + "type": "tools", "value": [ { - "description": "fetch_content(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", - "name": "TavilySearchComponent-fetch_content", + "args": { + "query": { + "default": "", + "description": "The search query you want to execute with Tavily.", + "title": "Query", + "type": "string" + } + }, + "description": "**Tavily Search** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", + "display_description": "**Tavily Search** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", + "display_name": "fetch_content_dataframe", + "name": "fetch_content_dataframe", + "readonly": false, + "status": true, "tags": [ - "TavilySearchComponent-fetch_content" - ] - }, - { - "description": "fetch_content_text(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", - "name": "TavilySearchComponent-fetch_content_text", - "tags": [ - "TavilySearchComponent-fetch_content_text" + "fetch_content_dataframe" ] } ] @@ -2812,9 +2013,9 @@ "type": "TavilySearchComponent" }, "dragging": false, - "id": "TavilySearchComponent-HW6b0", + "id": "TavilySearchComponent-jX5Zu", "measured": { - "height": 437, + "height": 316, "width": 320 }, "position": { @@ -2826,24 +2027,21 @@ }, { "data": { - "id": "OpenAIModel-dqLbl", + "id": "Agent-kSedw", "node": { "base_classes": [ - "LanguageModel", "Message" ], "beta": false, - "category": "models", + "category": "agents", "conditional_paths": [], "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "Agent", "documentation": "", "edited": false, "field_order": [ - "input_value", - "system_message", - "stream", + "agent_llm", "max_tokens", "model_kwargs", "json_mode", @@ -2851,56 +2049,136 @@ "openai_api_base", "api_key", "temperature", - "seed" + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" ], "frozen": false, - "icon": "OpenAI", - "key": "OpenAIModel", + "icon": "bot", + "key": "Agent", "legacy": false, - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, + "metadata": {}, "minimized": false, "output_types": [], "outputs": [ { "allows_loop": false, "cache": true, - "display_name": "Model Response", + "display_name": "Response", "group_outputs": false, - "method": "text_response", - "name": "text_output", + "method": "message_response", + "name": "response", + "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", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" } ], "pinned": false, - "score": 0.14285714285714285, + "score": 1.1732828199964098e-19, "template": { "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, "api_key": { "_input_type": "SecretStrInput", "advanced": false, @@ -2908,15 +2186,16 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -2934,14 +2213,32 @@ "show": true, "title_case": false, "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true }, "input_value": { - "_input_type": "MessageInput", + "_input_type": "MessageTextInput", "advanced": false, "display_name": "Input", "dynamic": false, - "info": "", + "info": "The input provided by the user for the agent to process.", "input_types": [ "Message" ], @@ -2953,7 +2250,7 @@ "required": false, "show": true, "title_case": false, - "tool_mode": false, + "tool_mode": true, "trace_as_input": true, "trace_as_metadata": true, "type": "str", @@ -2977,6 +2274,24 @@ "type": "bool", "value": false }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, "max_retries": { "_input_type": "IntInput", "advanced": true, @@ -3044,7 +2359,7 @@ "dialog_inputs": {}, "display_name": "Model Name", "dynamic": false, - "info": "", + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", "name": "model_name", "options": [ "gpt-4o-mini", @@ -3061,13 +2376,33 @@ ], "options_metadata": [], "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", "required": false, "show": true, "title_case": false, "tool_mode": false, "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" + "type": "int", + "value": 100 }, "openai_api_base": { "_input_type": "StrInput", @@ -3106,30 +2441,13 @@ "type": "int", "value": 1 }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { + "system_prompt": { "_input_type": "MultilineInput", "advanced": false, - "display_name": "System Message", + "copy_field": false, + "display_name": "Agent Instructions", "dynamic": false, - "info": "System message to pass to the model.", + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", "input_types": [ "Message" ], @@ -3137,7 +2455,7 @@ "list_add_label": "Add More", "load_from_db": false, "multiline": true, - "name": "system_message", + "name": "system_prompt", "placeholder": "", "required": false, "show": true, @@ -3146,11 +2464,11 @@ "trace_as_input": true, "trace_as_metadata": true, "type": "str", - "value": "" + "value": "You are a helpful AI assistant. Use the following information from a web search to answer the user's question. If the search results don't contain relevant information, say so and offer to help with something else." }, "temperature": { "_input_type": "SliderInput", - "advanced": false, + "advanced": true, "display_name": "Temperature", "dynamic": false, "info": "", @@ -3193,59 +2511,90 @@ "trace_as_metadata": true, "type": "int", "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true } }, "tool_mode": false }, - "selected_output": "text_output", "showNode": true, - "type": "OpenAIModel" + "type": "Agent" }, "dragging": false, - "id": "OpenAIModel-dqLbl", + "id": "Agent-kSedw", "measured": { - "height": 525, + "height": 594, "width": 320 }, "position": { - "x": 6411.984293767987, - "y": 2939.9259924956145 + "x": 5647.413945408762, + "y": 2815.554503226126 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "OpenAIModel-7yVxU", + "id": "LanguageModelComponent-Wd1th", "node": { "base_classes": [ "LanguageModel", "Message" ], "beta": false, - "category": "models", "conditional_paths": [], "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", + "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", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed" + "temperature" ], "frozen": false, - "icon": "OpenAI", - "key": "OpenAIModel", + "icon": "brain-circuit", "legacy": false, "metadata": { "keywords": [ @@ -3265,6 +2614,8 @@ "group_outputs": false, "method": "text_response", "name": "text_output", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -3279,6 +2630,8 @@ "group_outputs": false, "method": "build_model", "name": "model_output", + "options": null, + "required_inputs": null, "selected": "LanguageModel", "tool_mode": true, "types": [ @@ -3288,7 +2641,7 @@ } ], "pinned": false, - "score": 0.14285714285714285, + "priority": 0, "template": { "_type": "Component", "api_key": { @@ -3296,17 +2649,18 @@ "advanced": false, "display_name": "OpenAI API Key", "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", + "info": "Model Provider API key", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", - "required": true, + "real_time_refresh": true, + "required": false, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -3324,14 +2678,14 @@ "show": true, "title_case": false, "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" }, "input_value": { "_input_type": "MessageInput", "advanced": false, "display_name": "Input", "dynamic": false, - "info": "", + "info": "The input text to send to the model", "input_types": [ "Message" ], @@ -3349,92 +2703,14 @@ "type": "str", "value": "" }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, "model_name": { "_input_type": "DropdownInput", "advanced": false, - "combobox": true, + "combobox": false, "dialog_inputs": {}, "display_name": "Model Name", "dynamic": false, - "info": "", + "info": "Select the model to use", "name": "model_name", "options": [ "gpt-4o-mini", @@ -3446,62 +2722,61 @@ "gpt-4-turbo", "gpt-4-turbo-preview", "gpt-4", - "gpt-3.5-turbo", - "o1" + "gpt-3.5-turbo" ], "options_metadata": [], "placeholder": "", "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4.1-mini" + "value": "gpt-4o-mini" }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], "placeholder": "", + "real_time_refresh": true, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 + "value": "OpenAI" }, "stream": { "_input_type": "BoolInput", "advanced": true, "display_name": "Stream", "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", + "info": "Whether to stream the response", "list": false, "list_add_label": "Add More", "name": "stream", @@ -3516,10 +2791,11 @@ }, "system_message": { "_input_type": "MultilineInput", - "advanced": false, + "advanced": true, + "copy_field": false, "display_name": "System Message", "dynamic": false, - "info": "System message to pass to the model.", + "info": "A system message that helps set the behavior of the assistant", "input_types": [ "Message" ], @@ -3540,10 +2816,10 @@ }, "temperature": { "_input_type": "SliderInput", - "advanced": false, + "advanced": true, "display_name": "Temperature", "dynamic": false, - "info": "", + "info": "Controls randomness in responses", "max_label": "", "max_label_icon": "", "min_label": "", @@ -3565,57 +2841,330 @@ "tool_mode": false, "type": "slider", "value": 0.1 + } + }, + "tool_mode": false + }, + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-Wd1th", + "measured": { + "height": 451, + "width": 320 + }, + "position": { + "x": 6410.704770406965, + "y": 3006.328685380808 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-gDIcu", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Runs a language model given a specified provider. ", + "display_name": "Language Model", + "documentation": "", + "edited": false, + "field_order": [ + "provider", + "model_name", + "api_key", + "input_value", + "system_message", + "stream", + "temperature" + ], + "frozen": false, + "icon": "brain-circuit", + "legacy": false, + "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__" }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", + { + "allows_loop": false, + "cache": true, + "display_name": "Language Model", + "group_outputs": false, + "method": "build_model", + "name": "model_output", + "options": null, + "required_inputs": null, + "selected": "LanguageModel", + "tool_mode": true, + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "priority": 0, + "template": { + "_type": "Component", + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", + "info": "Model Provider API key", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", - "name": "timeout", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", "placeholder": "", "required": false, "show": true, "title_case": false, "tool_mode": false, "trace_as_metadata": true, - "type": "int", - "value": 700 + "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": "OpenAIModel" + "type": "LanguageModelComponent" }, "dragging": false, - "id": "OpenAIModel-7yVxU", + "id": "LanguageModelComponent-gDIcu", "measured": { - "height": 525, + "height": 451, "width": 320 }, "position": { - "x": 7206.924894456788, - "y": 2971.632992278429 + "x": 7232.710618447785, + "y": 2924.8555393803017 }, - "selected": false, + "selected": true, "type": "genericNode" } ], "viewport": { - "x": -1608.9301348469157, - "y": -773.9517359321869, - "zoom": 0.3648334507389854 + "x": -4443.353317209077, + "y": -1693.3791033708117, + "zoom": 0.6873430418367797 } }, "description": "Create engaging Instagram posts with AI-generated content and image prompts, streamlining social media content creation.", "endpoint_name": null, - "id": "071ed1b9-0719-4292-953a-f69b9f2bc7c4", + "id": "e0f800fd-1f3a-424f-a8db-cd879fa8fc98", "is_component": false, - "last_tested_version": "1.2.0", + "last_tested_version": "1.4.3", "name": "Instagram Copywriter", "tags": [ "content-generation", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json b/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json index fc2bce115..02d1ff930 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json @@ -3,11 +3,10 @@ "edges": [ { "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-0aGkQ", + "id": "Prompt-MK7WY", "name": "prompt", "output_types": [ "Message" @@ -15,27 +14,26 @@ }, "targetHandle": { "fieldName": "system_prompt", - "id": "Agent-DBNrp", + "id": "Agent-CBCVT", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-0aGkQ{œdataTypeœ:œPromptœ,œidœ:œPrompt-0aGkQœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-DBNrp{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-DBNrpœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__Prompt-MK7WY{œdataTypeœ:œPromptœ,œidœ:œPrompt-MK7WYœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-CBCVT{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-CBCVTœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-0aGkQ", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-0aGkQœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-DBNrp", - "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-DBNrpœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-MK7WY", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-MK7WYœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-CBCVT", + "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-CBCVTœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "needle", - "id": "needle-5GYmd", + "id": "needle-3GWxP", "name": "component_as_tool", "output_types": [ "Tool" @@ -43,27 +41,26 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-DBNrp", + "id": "Agent-CBCVT", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-needle-5GYmd{œdataTypeœ:œneedleœ,œidœ:œneedle-5GYmdœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-DBNrp{œfieldNameœ:œtoolsœ,œidœ:œAgent-DBNrpœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "xy-edge__needle-3GWxP{œdataTypeœ:œneedleœ,œidœ:œneedle-3GWxPœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-CBCVT{œfieldNameœ:œtoolsœ,œidœ:œAgent-CBCVTœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "needle-5GYmd", - "sourceHandle": "{œdataTypeœ: œneedleœ, œidœ: œneedle-5GYmdœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-DBNrp", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-DBNrpœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "needle-3GWxP", + "sourceHandle": "{œdataTypeœ: œneedleœ, œidœ: œneedle-3GWxPœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-CBCVT", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-CBCVTœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-cKEM6", + "id": "ChatInput-rqXHX", "name": "message", "output_types": [ "Message" @@ -71,27 +68,26 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-DBNrp", + "id": "Agent-CBCVT", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-cKEM6{œdataTypeœ:œChatInputœ,œidœ:œChatInput-cKEM6œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-DBNrp{œfieldNameœ:œinput_valueœ,œidœ:œAgent-DBNrpœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__ChatInput-rqXHX{œdataTypeœ:œChatInputœ,œidœ:œChatInput-rqXHXœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-CBCVT{œfieldNameœ:œinput_valueœ,œidœ:œAgent-CBCVTœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-cKEM6", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-cKEM6œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-DBNrp", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-DBNrpœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-rqXHX", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-rqXHXœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-CBCVT", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-CBCVTœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-DBNrp", + "id": "Agent-CBCVT", "name": "response", "output_types": [ "Message" @@ -99,7 +95,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-LTYD8", + "id": "ChatOutput-Acmbw", "inputTypes": [ "Data", "DataFrame", @@ -108,18 +104,18 @@ "type": "str" } }, - "id": "reactflow__edge-Agent-DBNrp{œdataTypeœ:œAgentœ,œidœ:œAgent-DBNrpœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-LTYD8{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-LTYD8œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__Agent-CBCVT{œdataTypeœ:œAgentœ,œidœ:œAgent-CBCVTœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Acmbw{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Acmbwœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-DBNrp", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-DBNrpœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-LTYD8", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-LTYD8œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-CBCVT", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-CBCVTœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-Acmbw", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Acmbwœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "note-n0kSK", + "id": "note-v8JKB", "node": { "description": "# Invoice Summarizer\n\nLeverage the **Needle Search API** and an **Agent** to gather and summarize your invoice data quickly and accurately.\n\n## Prerequisites\n\n* A **Collection** and an **API Key** from your [Needle.ai](https://needle-ai.com) deployment\n* An [OpenAI API key](https://platform.openai.com/)\n\n## Quickstart\n\n1. Load your invoices into your Needle Collection. \n\n2. In the **Needle Search** tool, add your **Needle Collection ID** and **Needle API Key**.\n\n3. In the **Agent** component, add your **OpenAI Key**.\n\n4. Open the **Playground** and query your invoices. The **Agent** component determines the correct query and search size for data retrieval.\n", "display_name": "", @@ -132,10 +128,10 @@ }, "dragging": false, "height": 632, - "id": "note-n0kSK", + "id": "note-v8JKB", "measured": { "height": 632, - "width": 583 + "width": 582 }, "position": { "x": -153.15585970276706, @@ -148,7 +144,7 @@ }, { "data": { - "id": "Prompt-0aGkQ", + "id": "Prompt-MK7WY", "node": { "base_classes": [ "Message" @@ -264,9 +260,9 @@ "type": "Prompt" }, "dragging": false, - "id": "Prompt-0aGkQ", + "id": "Prompt-MK7WY", "measured": { - "height": 330, + "height": 284, "width": 320 }, "position": { @@ -278,7 +274,7 @@ }, { "data": { - "id": "ChatOutput-LTYD8", + "id": "ChatOutput-Acmbw", "node": { "base_classes": [ "Message" @@ -574,9 +570,9 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-LTYD8", + "id": "ChatOutput-Acmbw", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -588,7 +584,7 @@ }, { "data": { - "id": "note-PDspc", + "id": "note-24qvs", "node": { "description": "### 💡 Add your OpenAI API key here 👇", "display_name": "", @@ -600,21 +596,21 @@ "type": "note" }, "dragging": false, - "id": "note-PDspc", + "id": "note-24qvs", "measured": { "height": 324, "width": 324 }, "position": { - "x": 1076.1571598578398, - "y": -389.50649266044195 + "x": 1084.4738832838511, + "y": -356.23959895639695 }, "selected": false, "type": "noteNode" }, { "data": { - "id": "note-Qcxtt", + "id": "note-jxdmT", "node": { "description": "### 💡 Add your Needle Search API key here 👇", "display_name": "", @@ -627,10 +623,10 @@ }, "dragging": false, "height": 324, - "id": "note-Qcxtt", + "id": "note-jxdmT", "measured": { "height": 324, - "width": 401 + "width": 402 }, "position": { "x": 500.88806568161635, @@ -643,7 +639,7 @@ }, { "data": { - "id": "needle-5GYmd", + "id": "needle-3GWxP", "node": { "base_classes": [ "Message" @@ -674,6 +670,7 @@ "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": null, "method": "to_toolkit", "name": "component_as_tool", @@ -828,9 +825,9 @@ "showNode": true, "type": "needle" }, - "id": "needle-5GYmd", + "id": "needle-3GWxP", "measured": { - "height": 495, + "height": 465, "width": 320 }, "position": { @@ -842,7 +839,7 @@ }, { "data": { - "id": "ChatInput-cKEM6", + "id": "ChatInput-rqXHX", "node": { "base_classes": [ "Message" @@ -1141,9 +1138,9 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-cKEM6", + "id": "ChatInput-rqXHX", "measured": { - "height": 230, + "height": 204, "width": 320 }, "position": { @@ -1155,7 +1152,7 @@ }, { "data": { - "id": "Agent-DBNrp", + "id": "Agent-CBCVT", "node": { "base_classes": [ "Message" @@ -1181,19 +1178,13 @@ "max_retries", "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, @@ -1208,8 +1199,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1219,7 +1213,7 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, + "score": 0.027777777777777776, "template": { "_type": "Component", "add_current_date_tool": { @@ -1228,7 +1222,6 @@ "display_name": "Current Date", "dynamic": false, "info": "If true, will add a tool to the agent that returns the current date.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "add_current_date_tool", @@ -1284,30 +1277,18 @@ "Custom" ], "options_metadata": [ - { - "icon": "Amazon" - }, { "icon": "Anthropic" }, - { - "icon": "Azure" - }, { "icon": "GoogleGenerativeAI" }, { "icon": "Groq" }, - { - "icon": "NVIDIA" - }, { "icon": "OpenAI" }, - { - "icon": "SambaNova" - }, { "icon": "brain" } @@ -1317,6 +1298,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1329,15 +1311,16 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1355,7 +1338,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1363,7 +1346,6 @@ "display_name": "Handle Parse Errors", "dynamic": false, "info": "Should the Agent fix errors when reading user input for better processing?", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "handle_parsing_errors", @@ -1405,7 +1387,6 @@ "display_name": "JSON Mode", "dynamic": false, "info": "If True, it will output JSON regardless of passing a schema.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "json_mode", @@ -1424,7 +1405,6 @@ "display_name": "Max Iterations", "dynamic": false, "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "max_iterations", @@ -1443,7 +1423,6 @@ "display_name": "Max Retries", "dynamic": false, "info": "The maximum number of retries to make when generating.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "max_retries", @@ -1462,7 +1441,6 @@ "display_name": "Max Tokens", "dynamic": false, "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "max_tokens", @@ -1481,77 +1459,12 @@ "type": "int", "value": "" }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, "display_name": "Model Kwargs", "dynamic": false, "info": "Additional keyword arguments to pass to the model.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "model_kwargs", @@ -1572,7 +1485,6 @@ "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "input_types": [], "name": "model_name", "options": [ "gpt-4o-mini", @@ -1597,15 +1509,14 @@ "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4.1" + "value": "gpt-4o" }, "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", - "input_types": [], + "info": "Number of chat history messages to retrieve.", "list": false, "list_add_label": "Add More", "name": "n_messages", @@ -1624,7 +1535,6 @@ "display_name": "OpenAI API Base", "dynamic": false, "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "input_types": [], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1638,37 +1548,12 @@ "type": "str", "value": "" }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "input_types": [], - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, "seed": { "_input_type": "IntInput", "advanced": true, "display_name": "Seed", "dynamic": false, "info": "The seed controls the reproducibility of the job.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "seed", @@ -1681,104 +1566,6 @@ "type": "int", "value": 1 }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "input_types": [ - "Message" - ], - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "options_metadata": [], - "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, - "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": "" - }, - "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, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, @@ -1810,7 +1597,6 @@ "display_name": "Temperature", "dynamic": false, "info": "", - "input_types": [], "max_label": "", "max_label_icon": "", "min_label": "", @@ -1833,38 +1619,12 @@ "type": "slider", "value": 0.1 }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "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}" - }, "timeout": { "_input_type": "IntInput", "advanced": true, "display_name": "Timeout", "dynamic": false, "info": "The timeout for requests to OpenAI completion API.", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "timeout", @@ -1903,7 +1663,6 @@ "display_name": "Verbose", "dynamic": false, "info": "", - "input_types": [], "list": false, "list_add_label": "Add More", "name": "verbose", @@ -1919,34 +1678,34 @@ }, "tool_mode": false }, - "selected_output": "response", "showNode": true, "type": "Agent" }, - "id": "Agent-DBNrp", + "dragging": false, + "id": "Agent-CBCVT", "measured": { - "height": 624, + "height": 594, "width": 320 }, "position": { - "x": 1095, - "y": -330 + "x": 1091.580413056917, + "y": -301.3655700498317 }, "selected": false, "type": "genericNode" } ], "viewport": { - "x": 150.31260070182884, - "y": 468.5915273517045, - "zoom": 0.6157949221457367 + "x": -35.507548688879524, + "y": 491.41656271070804, + "zoom": 0.7214379621227387 } }, "description": "Your AI Agent Accountant - Leverage Needle with Langflows Agent.", "endpoint_name": null, - "id": "2803158e-d8ca-4615-bc9a-0299886b7225", + "id": "4c77bc1e-3ef0-4ea2-8192-ee3a8b1c5522", "is_component": false, - "last_tested_version": "1.3.4", + "last_tested_version": "1.4.3", "name": "Invoice Summarizer", "tags": [ "chatbots", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json index 8ff44978a..6b545e34f 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json @@ -1,125 +1,13 @@ { "data": { "edges": [ - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-Vu7qu", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-ZGDpX", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-Vu7qu{œdataTypeœ:œChatInputœ,œidœ:œChatInput-Vu7quœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-ZGDpX{œfieldNameœ:œinput_valueœ,œidœ:œAgent-ZGDpXœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-Vu7qu", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-Vu7quœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-ZGDpX", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-ZGDpXœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Agent", - "id": "Agent-ZGDpX", - "name": "response", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "StructuredOutput-Aph6K", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Agent-ZGDpX{œdataTypeœ:œAgentœ,œidœ:œAgent-ZGDpXœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-StructuredOutput-Aph6K{œfieldNameœ:œinput_valueœ,œidœ:œStructuredOutput-Aph6Kœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Agent-ZGDpX", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-ZGDpXœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "StructuredOutput-Aph6K", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œStructuredOutput-Aph6Kœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "TavilySearchComponent", - "id": "TavilySearchComponent-Q9JKS", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-ZGDpX", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-TavilySearchComponent-Q9JKS{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-Q9JKSœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-ZGDpX{œfieldNameœ:œtoolsœ,œidœ:œAgent-ZGDpXœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "TavilySearchComponent-Q9JKS", - "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-Q9JKSœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-ZGDpX", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-ZGDpXœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-YQpWE", - "name": "model_output", - "output_types": [ - "LanguageModel" - ] - }, - "targetHandle": { - "fieldName": "llm", - "id": "StructuredOutput-Aph6K", - "inputTypes": [ - "LanguageModel" - ], - "type": "other" - } - }, - "id": "reactflow__edge-OpenAIModel-YQpWE{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-YQpWEœ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-StructuredOutput-Aph6K{œfieldNameœ:œllmœ,œidœ:œStructuredOutput-Aph6Kœ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}", - "selected": false, - "source": "OpenAIModel-YQpWE", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-YQpWEœ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}", - "target": "StructuredOutput-Aph6K", - "targetHandle": "{œfieldNameœ: œllmœ, œidœ: œStructuredOutput-Aph6Kœ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}" - }, { "animated": false, "className": "", "data": { "sourceHandle": { "dataType": "parser", - "id": "parser-0YWi5", + "id": "parser-0bZeT", "name": "parsed_text", "output_types": [ "Message" @@ -127,7 +15,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-CfBiH", + "id": "ChatOutput-Iyjxr", "inputTypes": [ "Data", "DataFrame", @@ -136,12 +24,12 @@ "type": "str" } }, - "id": "reactflow__edge-parser-0YWi5{œdataTypeœ:œparserœ,œidœ:œparser-0YWi5œ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-CfBiH{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-CfBiHœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-parser-0bZeT{œdataTypeœ:œparserœ,œidœ:œparser-0bZeTœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Iyjxr{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Iyjxrœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "parser-0YWi5", - "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-0YWi5œ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-CfBiH", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-CfBiHœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "parser-0bZeT", + "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-0bZeTœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-Iyjxr", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Iyjxrœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -149,7 +37,7 @@ "data": { "sourceHandle": { "dataType": "StructuredOutput", - "id": "StructuredOutput-Aph6K", + "id": "StructuredOutput-Q7VB2", "name": "structured_output", "output_types": [ "Data" @@ -157,7 +45,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "parser-0YWi5", + "id": "parser-0bZeT", "inputTypes": [ "DataFrame", "Data" @@ -165,12 +53,114 @@ "type": "other" } }, - "id": "xy-edge__StructuredOutput-Aph6K{œdataTypeœ:œStructuredOutputœ,œidœ:œStructuredOutput-Aph6Kœ,œnameœ:œstructured_outputœ,œoutput_typesœ:[œDataœ]}-parser-0YWi5{œfieldNameœ:œinput_dataœ,œidœ:œparser-0YWi5œ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-StructuredOutput-Q7VB2{œdataTypeœ:œStructuredOutputœ,œidœ:œStructuredOutput-Q7VB2œ,œnameœ:œstructured_outputœ,œoutput_typesœ:[œDataœ]}-parser-0bZeT{œfieldNameœ:œinput_dataœ,œidœ:œparser-0bZeTœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", "selected": false, - "source": "StructuredOutput-Aph6K", - "sourceHandle": "{œdataTypeœ: œStructuredOutputœ, œidœ: œStructuredOutput-Aph6Kœ, œnameœ: œstructured_outputœ, œoutput_typesœ: [œDataœ]}", - "target": "parser-0YWi5", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-0YWi5œ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" + "source": "StructuredOutput-Q7VB2", + "sourceHandle": "{œdataTypeœ: œStructuredOutputœ, œidœ: œStructuredOutput-Q7VB2œ, œnameœ: œstructured_outputœ, œoutput_typesœ: [œDataœ]}", + "target": "parser-0bZeT", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-0bZeTœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-06zGA", + "name": "model_output", + "output_types": [ + "LanguageModel" + ] + }, + "targetHandle": { + "fieldName": "llm", + "id": "StructuredOutput-Q7VB2", + "inputTypes": [ + "LanguageModel" + ], + "type": "other" + } + }, + "id": "xy-edge__LanguageModelComponent-06zGA{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-06zGAœ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-StructuredOutput-Q7VB2{œfieldNameœ:œllmœ,œidœ:œStructuredOutput-Q7VB2œ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}", + "selected": false, + "source": "LanguageModelComponent-06zGA", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-06zGAœ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}", + "target": "StructuredOutput-Q7VB2", + "targetHandle": "{œfieldNameœ: œllmœ, œidœ: œStructuredOutput-Q7VB2œ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "TavilySearchComponent", + "id": "TavilySearchComponent-6v78l", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-rpeeh", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__TavilySearchComponent-6v78l{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-6v78lœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-rpeeh{œfieldNameœ:œtoolsœ,œidœ:œAgent-rpeehœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "source": "TavilySearchComponent-6v78l", + "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-6v78lœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-rpeeh", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-rpeehœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-hsPEi", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-rpeeh", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__ChatInput-hsPEi{œdataTypeœ:œChatInputœ,œidœ:œChatInput-hsPEiœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-rpeeh{œfieldNameœ:œinput_valueœ,œidœ:œAgent-rpeehœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "ChatInput-hsPEi", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-hsPEiœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-rpeeh", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-rpeehœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Agent", + "id": "Agent-rpeeh", + "name": "response", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "StructuredOutput-Q7VB2", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Agent-rpeeh{œdataTypeœ:œAgentœ,œidœ:œAgent-rpeehœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-StructuredOutput-Q7VB2{œfieldNameœ:œinput_valueœ,œidœ:œStructuredOutput-Q7VB2œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Agent-rpeeh", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-rpeehœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "StructuredOutput-Q7VB2", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œStructuredOutput-Q7VB2œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ @@ -178,7 +168,7 @@ "data": { "description": "Get chat inputs from the Playground.", "display_name": "Chat Input", - "id": "ChatInput-Vu7qu", + "id": "ChatInput-hsPEi", "node": { "base_classes": [ "Message" @@ -455,7 +445,7 @@ }, "dragging": false, "height": 234, - "id": "ChatInput-Vu7qu", + "id": "ChatInput-hsPEi", "measured": { "height": 234, "width": 320 @@ -476,7 +466,7 @@ "data": { "description": "Display a chat message in the Playground.", "display_name": "Chat Output", - "id": "ChatOutput-CfBiH", + "id": "ChatOutput-Iyjxr", "node": { "base_classes": [ "Message" @@ -759,7 +749,7 @@ }, "dragging": false, "height": 234, - "id": "ChatOutput-CfBiH", + "id": "ChatOutput-Iyjxr", "measured": { "height": 234, "width": 320 @@ -778,7 +768,7 @@ }, { "data": { - "id": "note-wiaOc", + "id": "note-1Ekot", "node": { "description": "# Market Research\nThis flow helps you gather comprehensive information about companies for sales and business intelligence purposes.\n\n## Prerequisites\n\n- **[Tavily API Key](https://docs.tavily.com/welcome)**\n- **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quickstart\n\n1. Add your **OpenAI API key** to the **OpenAI** model and **Agent** components.\n2. Add your **Tavily API key** to the **Tavily Search** component.\n3. In the **Chat Input**, enter a company name you want to research.\n4. Open the **Playground** and research the company. The **Structured Output** component transforms the raw LLM response into structured data, and the **Parser** component presents the data as text for the **Chat output** component to present.", "display_name": "", @@ -791,10 +781,10 @@ }, "dragging": false, "height": 671, - "id": "note-wiaOc", + "id": "note-1Ekot", "measured": { "height": 671, - "width": 660 + "width": 659 }, "position": { "x": -226.74339309333172, @@ -817,7 +807,7 @@ "data": { "description": "Transforms LLM responses into **structured data formats**. Ideal for extracting specific information or creating consistent outputs.", "display_name": "Structured Output", - "id": "StructuredOutput-Aph6K", + "id": "StructuredOutput-Q7VB2", "node": { "base_classes": [ "Data", @@ -1128,7 +1118,7 @@ }, "dragging": false, "height": 541, - "id": "StructuredOutput-Aph6K", + "id": "StructuredOutput-Q7VB2", "measured": { "height": 541, "width": 320 @@ -1145,696 +1135,11 @@ "type": "genericNode", "width": 320 }, - { - "data": { - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "id": "Agent-ZGDpX", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "output_schema", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "output_parser", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "lf_version": "1.2.0", - "metadata": {}, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Anthropic", - "Google Generative AI", - "Groq", - "OpenAI", - "Custom" - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "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 langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "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 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are an expert business research agent. Your task is to gather comprehensive information about companies. When researching a company, focus on the following key areas: 1. Basic company information (website, domain, social presence) 2. Product and pricing information 3. Technical capabilities and integrations 4. Market positioning and target audience 5. Key features and offerings For the company/domain provided, search thoroughly and provide detailed information about: - Their main website and domain - Their pricing structure - Product features and capabilities - Market presence and focus - Technical offerings like APIs - Social media presence, especially LinkedIn Search comprehensively and provide detailed, factual information that will help determine: - Pricing tiers and structure - Whether they offer free trials - If they have enterprise solutions - Their technical capabilities - Their primary market (B2B/B2C) INPUT: {input} Respond with detailed, factual information about these aspects, avoiding speculation. Include direct quotes or specific information you find." - }, - "temperature": { - "_input_type": "FloatInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "list": false, - "name": "temperature", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "float", - "value": 0.1 - }, - "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}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "type": "Agent" - }, - "dragging": false, - "height": 650, - "id": "Agent-ZGDpX", - "measured": { - "height": 650, - "width": 320 - }, - "position": { - "x": 1287.5681517817056, - "y": 519.8701526087884 - }, - "selected": false, - "type": "genericNode", - "width": 320 - }, { "data": { "description": "**Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", "display_name": "Tavily AI Search", - "id": "TavilySearchComponent-Q9JKS", + "id": "TavilySearchComponent-6v78l", "node": { "base_classes": [ "Data", @@ -1893,7 +1198,7 @@ "dynamic": false, "info": "Your Tavily API Key.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -2215,7 +1520,7 @@ "type": "TavilySearchComponent" }, "dragging": false, - "id": "TavilySearchComponent-Q9JKS", + "id": "TavilySearchComponent-6v78l", "measured": { "height": 316, "width": 320 @@ -2229,398 +1534,7 @@ }, { "data": { - "id": "OpenAIModel-YQpWE", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "category": "models", - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "key": "OpenAIModel", - "legacy": false, - "lf_version": "1.2.0", - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": null, - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 0.14285714285714285, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - } - }, - "tool_mode": false - }, - "selected_output": "model_output", - "showNode": true, - "type": "OpenAIModel" - }, - "dragging": false, - "id": "OpenAIModel-YQpWE", - "measured": { - "height": 539, - "width": 320 - }, - "position": { - "x": 1282.8196790852462, - "y": 1161.6622506143262 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "parser-0YWi5", + "id": "parser-0bZeT", "node": { "base_classes": [ "Message" @@ -2781,9 +1695,9 @@ "type": "parser" }, "dragging": false, - "id": "parser-0YWi5", + "id": "parser-0bZeT", "measured": { - "height": 360, + "height": 361, "width": 320 }, "position": { @@ -2792,17 +1706,853 @@ }, "selected": false, "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-06zGA", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Runs a language model given a specified provider. ", + "display_name": "Language Model", + "documentation": "", + "edited": false, + "field_order": [ + "provider", + "model_name", + "api_key", + "input_value", + "system_message", + "stream", + "temperature" + ], + "frozen": false, + "icon": "brain-circuit", + "legacy": false, + "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, + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "allows_loop": false, + "cache": true, + "display_name": "Language Model", + "group_outputs": false, + "method": "build_model", + "name": "model_output", + "options": null, + "required_inputs": null, + "selected": "LanguageModel", + "tool_mode": true, + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "priority": 0, + "template": { + "_type": "Component", + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "Model Provider API key", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "_input_type": "MultilineInput", + "advanced": 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": "model_output", + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-06zGA", + "measured": { + "height": 451, + "width": 320 + }, + "position": { + "x": 1238.9336326592597, + "y": 1187.129728383852 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "Agent-rpeeh", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "category": "agents", + "conditional_paths": [], + "custom_fields": {}, + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "Agent", + "documentation": "", + "edited": false, + "field_order": [ + "agent_llm", + "max_tokens", + "model_kwargs", + "json_mode", + "model_name", + "openai_api_base", + "api_key", + "temperature", + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" + ], + "frozen": false, + "icon": "bot", + "key": "Agent", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Response", + "group_outputs": false, + "method": "message_response", + "name": "response", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 1.1732828199964098e-19, + "template": { + "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "input_value": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input provided by the user for the agent to process.", + "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": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "json_mode": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "JSON Mode", + "dynamic": false, + "info": "If True, it will output JSON regardless of passing a schema.", + "list": false, + "list_add_label": "Add More", + "name": "json_mode", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, + "max_retries": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "The maximum number of retries to make when generating.", + "list": false, + "list_add_label": "Add More", + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_tokens": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "list_add_label": "Add More", + "name": "max_tokens", + "placeholder": "", + "range_spec": { + "max": 128000, + "min": 0, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "Additional keyword arguments to pass to the model.", + "list": false, + "list_add_label": "Add More", + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": true, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo", + "o1" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "openai_api_base": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "seed": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "list_add_label": "Add More", + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "system_prompt": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Agent Instructions", + "dynamic": false, + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_prompt", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "You are a helpful assistant that can use tools to answer questions and perform tasks." + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "The timeout for requests to OpenAI completion API.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "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": "Agent" + }, + "dragging": false, + "id": "Agent-rpeeh", + "measured": { + "height": 594, + "width": 320 + }, + "position": { + "x": 1260.684187419134, + "y": 453.54283602809056 + }, + "selected": false, + "type": "genericNode" } ], "viewport": { - "x": -93.26437689350178, - "y": -217.58870925998986, - "zoom": 0.5616361094335138 + "x": -241.57114311371276, + "y": -33.37213562537306, + "zoom": 0.5057342270778734 } }, "description": "Researches companies, extracts key business data, and presents structured information for efficient analysis. ", "endpoint_name": null, - "id": "33ed74a4-250a-45d3-aebd-8eea096cc3c5", + "id": "b8fa39d0-e814-4e2c-ad35-f57f75abbc0a", "is_component": false, "last_tested_version": "1.4.3", "name": "Market Research", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json b/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json index c771753d2..7b59a19d7 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json @@ -1,101 +1,13 @@ { "data": { "edges": [ - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-Vzk5z", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-adSHw", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-Vzk5z{œdataTypeœ:œPromptœ,œidœ:œPrompt-Vzk5zœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-adSHw{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-adSHwœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-Vzk5z", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-Vzk5zœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-adSHw", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-adSHwœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-adSHw", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-NbY9b", - "inputTypes": [ - "Data", - "DataFrame", - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-adSHw{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-adSHwœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-NbY9b{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-NbY9bœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "OpenAIModel-adSHw", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-adSHwœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-NbY9b", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-NbY9bœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-A8LqG", - "name": "text_output", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-paHng", - "inputTypes": [ - "Data", - "DataFrame", - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-OpenAIModel-A8LqG{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-A8LqGœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-paHng{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-paHngœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "OpenAIModel-A8LqG", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-A8LqGœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-paHng", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-paHngœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" - }, { "animated": false, "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-xfgsq", + "id": "ChatInput-VajCb", "name": "message", "output_types": [ "Message" @@ -103,7 +15,7 @@ }, "targetHandle": { "fieldName": "input", - "id": "Prompt-iKEvN", + "id": "Prompt-qm57P", "inputTypes": [ "Message", "Text" @@ -111,40 +23,12 @@ "type": "str" } }, - "id": "reactflow__edge-ChatInput-xfgsq{œdataTypeœ:œChatInputœ,œidœ:œChatInput-xfgsqœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-iKEvN{œfieldNameœ:œinputœ,œidœ:œPrompt-iKEvNœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-VajCb{œdataTypeœ:œChatInputœ,œidœ:œChatInput-VajCbœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-qm57P{œfieldNameœ:œinputœ,œidœ:œPrompt-qm57Pœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-xfgsq", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-xfgsqœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-iKEvN", - "targetHandle": "{œfieldNameœ: œinputœ, œidœ: œPrompt-iKEvNœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-iKEvN", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-A8LqG", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-iKEvN{œdataTypeœ:œPromptœ,œidœ:œPrompt-iKEvNœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-A8LqG{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-A8LqGœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-iKEvN", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-iKEvNœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-A8LqG", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-A8LqGœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-VajCb", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-VajCbœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-qm57P", + "targetHandle": "{œfieldNameœ: œinputœ, œidœ: œPrompt-qm57Pœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -152,7 +36,7 @@ "data": { "sourceHandle": { "dataType": "AssemblyAITranscriptionJobCreator", - "id": "AssemblyAITranscriptionJobCreator-hXp0S", + "id": "AssemblyAITranscriptionJobCreator-fAs7l", "name": "transcript_id", "output_types": [ "Data" @@ -160,19 +44,19 @@ }, "targetHandle": { "fieldName": "transcript_id", - "id": "AssemblyAITranscriptionJobPoller-VCkre", + "id": "AssemblyAITranscriptionJobPoller-GaXh2", "inputTypes": [ "Data" ], "type": "other" } }, - "id": "reactflow__edge-AssemblyAITranscriptionJobCreator-hXp0S{œdataTypeœ:œAssemblyAITranscriptionJobCreatorœ,œidœ:œAssemblyAITranscriptionJobCreator-hXp0Sœ,œnameœ:œtranscript_idœ,œoutput_typesœ:[œDataœ]}-AssemblyAITranscriptionJobPoller-VCkre{œfieldNameœ:œtranscript_idœ,œidœ:œAssemblyAITranscriptionJobPoller-VCkreœ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-AssemblyAITranscriptionJobCreator-fAs7l{œdataTypeœ:œAssemblyAITranscriptionJobCreatorœ,œidœ:œAssemblyAITranscriptionJobCreator-fAs7lœ,œnameœ:œtranscript_idœ,œoutput_typesœ:[œDataœ]}-AssemblyAITranscriptionJobPoller-GaXh2{œfieldNameœ:œtranscript_idœ,œidœ:œAssemblyAITranscriptionJobPoller-GaXh2œ,œinputTypesœ:[œDataœ],œtypeœ:œotherœ}", "selected": false, - "source": "AssemblyAITranscriptionJobCreator-hXp0S", - "sourceHandle": "{œdataTypeœ: œAssemblyAITranscriptionJobCreatorœ, œidœ: œAssemblyAITranscriptionJobCreator-hXp0Sœ, œnameœ: œtranscript_idœ, œoutput_typesœ: [œDataœ]}", - "target": "AssemblyAITranscriptionJobPoller-VCkre", - "targetHandle": "{œfieldNameœ: œtranscript_idœ, œidœ: œAssemblyAITranscriptionJobPoller-VCkreœ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" + "source": "AssemblyAITranscriptionJobCreator-fAs7l", + "sourceHandle": "{œdataTypeœ: œAssemblyAITranscriptionJobCreatorœ, œidœ: œAssemblyAITranscriptionJobCreator-fAs7lœ, œnameœ: œtranscript_idœ, œoutput_typesœ: [œDataœ]}", + "target": "AssemblyAITranscriptionJobPoller-GaXh2", + "targetHandle": "{œfieldNameœ: œtranscript_idœ, œidœ: œAssemblyAITranscriptionJobPoller-GaXh2œ, œinputTypesœ: [œDataœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -180,7 +64,7 @@ "data": { "sourceHandle": { "dataType": "AssemblyAITranscriptionJobPoller", - "id": "AssemblyAITranscriptionJobPoller-VCkre", + "id": "AssemblyAITranscriptionJobPoller-GaXh2", "name": "transcription_result", "output_types": [ "Data" @@ -188,7 +72,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "parser-uRyvX", + "id": "parser-YtYmK", "inputTypes": [ "DataFrame", "Data" @@ -196,12 +80,12 @@ "type": "other" } }, - "id": "reactflow__edge-AssemblyAITranscriptionJobPoller-VCkre{œdataTypeœ:œAssemblyAITranscriptionJobPollerœ,œidœ:œAssemblyAITranscriptionJobPoller-VCkreœ,œnameœ:œtranscription_resultœ,œoutput_typesœ:[œDataœ]}-parser-uRyvX{œfieldNameœ:œinput_dataœ,œidœ:œparser-uRyvXœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-AssemblyAITranscriptionJobPoller-GaXh2{œdataTypeœ:œAssemblyAITranscriptionJobPollerœ,œidœ:œAssemblyAITranscriptionJobPoller-GaXh2œ,œnameœ:œtranscription_resultœ,œoutput_typesœ:[œDataœ]}-parser-YtYmK{œfieldNameœ:œinput_dataœ,œidœ:œparser-YtYmKœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", "selected": false, - "source": "AssemblyAITranscriptionJobPoller-VCkre", - "sourceHandle": "{œdataTypeœ: œAssemblyAITranscriptionJobPollerœ, œidœ: œAssemblyAITranscriptionJobPoller-VCkreœ, œnameœ: œtranscription_resultœ, œoutput_typesœ: [œDataœ]}", - "target": "parser-uRyvX", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-uRyvXœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" + "source": "AssemblyAITranscriptionJobPoller-GaXh2", + "sourceHandle": "{œdataTypeœ: œAssemblyAITranscriptionJobPollerœ, œidœ: œAssemblyAITranscriptionJobPoller-GaXh2œ, œnameœ: œtranscription_resultœ, œoutput_typesœ: [œDataœ]}", + "target": "parser-YtYmK", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-YtYmKœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -209,7 +93,7 @@ "data": { "sourceHandle": { "dataType": "parser", - "id": "parser-uRyvX", + "id": "parser-YtYmK", "name": "parsed_text", "output_types": [ "Message" @@ -217,7 +101,7 @@ }, "targetHandle": { "fieldName": "transcript", - "id": "Prompt-Vzk5z", + "id": "Prompt-Nc0MB", "inputTypes": [ "Message", "Text" @@ -225,12 +109,12 @@ "type": "str" } }, - "id": "reactflow__edge-parser-uRyvX{œdataTypeœ:œparserœ,œidœ:œparser-uRyvXœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-Vzk5z{œfieldNameœ:œtranscriptœ,œidœ:œPrompt-Vzk5zœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-parser-YtYmK{œdataTypeœ:œparserœ,œidœ:œparser-YtYmKœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-Nc0MB{œfieldNameœ:œtranscriptœ,œidœ:œPrompt-Nc0MBœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "parser-uRyvX", - "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-uRyvXœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-Vzk5z", - "targetHandle": "{œfieldNameœ: œtranscriptœ, œidœ: œPrompt-Vzk5zœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "source": "parser-YtYmK", + "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-YtYmKœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-Nc0MB", + "targetHandle": "{œfieldNameœ: œtranscriptœ, œidœ: œPrompt-Nc0MBœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -238,7 +122,7 @@ "data": { "sourceHandle": { "dataType": "parser", - "id": "parser-uRyvX", + "id": "parser-YtYmK", "name": "parsed_text", "output_types": [ "Message" @@ -246,7 +130,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-5pvPL", + "id": "ChatOutput-m5kak", "inputTypes": [ "Data", "DataFrame", @@ -255,18 +139,20 @@ "type": "str" } }, - "id": "reactflow__edge-parser-uRyvX{œdataTypeœ:œparserœ,œidœ:œparser-uRyvXœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-5pvPL{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-5pvPLœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-parser-YtYmK{œdataTypeœ:œparserœ,œidœ:œparser-YtYmKœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-m5kak{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-m5kakœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "parser-uRyvX", - "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-uRyvXœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-5pvPL", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-5pvPLœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "parser-YtYmK", + "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-YtYmKœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-m5kak", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-m5kakœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { + "animated": false, + "className": "", "data": { "sourceHandle": { "dataType": "Memory", - "id": "Memory-YN8aN", + "id": "Memory-W2jhq", "name": "dataframe", "output_types": [ "DataFrame" @@ -274,7 +160,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "TypeConverterComponent-MzSbu", + "id": "TypeConverterComponent-E7sN7", "inputTypes": [ "Message", "Data", @@ -283,17 +169,20 @@ "type": "other" } }, - "id": "xy-edge__Memory-YN8aN{œdataTypeœ:œMemoryœ,œidœ:œMemory-YN8aNœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-TypeConverterComponent-MzSbu{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-MzSbuœ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}", - "source": "Memory-YN8aN", - "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-YN8aNœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", - "target": "TypeConverterComponent-MzSbu", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-MzSbuœ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}" + "id": "reactflow__edge-Memory-W2jhq{œdataTypeœ:œMemoryœ,œidœ:œMemory-W2jhqœ,œnameœ:œdataframeœ,œoutput_typesœ:[œDataFrameœ]}-TypeConverterComponent-E7sN7{œfieldNameœ:œinput_dataœ,œidœ:œTypeConverterComponent-E7sN7œ,œinputTypesœ:[œMessageœ,œDataœ,œDataFrameœ],œtypeœ:œotherœ}", + "selected": false, + "source": "Memory-W2jhq", + "sourceHandle": "{œdataTypeœ: œMemoryœ, œidœ: œMemory-W2jhqœ, œnameœ: œdataframeœ, œoutput_typesœ: [œDataFrameœ]}", + "target": "TypeConverterComponent-E7sN7", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œTypeConverterComponent-E7sN7œ, œinputTypesœ: [œMessageœ, œDataœ, œDataFrameœ], œtypeœ: œotherœ}" }, { + "animated": false, + "className": "", "data": { "sourceHandle": { "dataType": "TypeConverterComponent", - "id": "TypeConverterComponent-MzSbu", + "id": "TypeConverterComponent-E7sN7", "name": "message_output", "output_types": [ "Message" @@ -301,7 +190,7 @@ }, "targetHandle": { "fieldName": "history", - "id": "Prompt-iKEvN", + "id": "Prompt-qm57P", "inputTypes": [ "Message", "Text" @@ -309,17 +198,126 @@ "type": "str" } }, - "id": "xy-edge__TypeConverterComponent-MzSbu{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-MzSbuœ,œnameœ:œmessage_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-iKEvN{œfieldNameœ:œhistoryœ,œidœ:œPrompt-iKEvNœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "source": "TypeConverterComponent-MzSbu", - "sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-MzSbuœ, œnameœ: œmessage_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-iKEvN", - "targetHandle": "{œfieldNameœ: œhistoryœ, œidœ: œPrompt-iKEvNœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "id": "reactflow__edge-TypeConverterComponent-E7sN7{œdataTypeœ:œTypeConverterComponentœ,œidœ:œTypeConverterComponent-E7sN7œ,œnameœ:œmessage_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-qm57P{œfieldNameœ:œhistoryœ,œidœ:œPrompt-qm57Pœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "selected": false, + "source": "TypeConverterComponent-E7sN7", + "sourceHandle": "{œdataTypeœ: œTypeConverterComponentœ, œidœ: œTypeConverterComponent-E7sN7œ, œnameœ: œmessage_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-qm57P", + "targetHandle": "{œfieldNameœ: œhistoryœ, œidœ: œPrompt-qm57Pœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-Nc0MB", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "LanguageModelComponent-sdJZz", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Prompt-Nc0MB{œdataTypeœ:œPromptœ,œidœ:œPrompt-Nc0MBœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-sdJZz{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-sdJZzœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Prompt-Nc0MB", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-Nc0MBœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-sdJZz", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-sdJZzœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-sdJZz", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-LTpUg", + "inputTypes": [ + "Data", + "DataFrame", + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__LanguageModelComponent-sdJZz{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-sdJZzœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-LTpUg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-LTpUgœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "LanguageModelComponent-sdJZz", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-sdJZzœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-LTpUg", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-LTpUgœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-qm57P", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "LanguageModelComponent-LzdL4", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Prompt-qm57P{œdataTypeœ:œPromptœ,œidœ:œPrompt-qm57Pœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-LzdL4{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-LzdL4œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "Prompt-qm57P", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-qm57Pœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-LzdL4", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-LzdL4œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-LzdL4", + "name": "text_output", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-SLRFg", + "inputTypes": [ + "Data", + "DataFrame", + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__LanguageModelComponent-LzdL4{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-LzdL4œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-SLRFg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-SLRFgœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "source": "LanguageModelComponent-LzdL4", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-LzdL4œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-SLRFg", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-SLRFgœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "AssemblyAITranscriptionJobPoller-VCkre", + "id": "AssemblyAITranscriptionJobPoller-GaXh2", "node": { "base_classes": [ "Data" @@ -450,9 +448,9 @@ "showNode": true, "type": "AssemblyAITranscriptionJobPoller" }, - "id": "AssemblyAITranscriptionJobPoller-VCkre", + "id": "AssemblyAITranscriptionJobPoller-GaXh2", "measured": { - "height": 263, + "height": 264, "width": 320 }, "position": { @@ -464,7 +462,7 @@ }, { "data": { - "id": "ParseData-X7r7s", + "id": "ParseData-ZQpM3", "node": { "base_classes": [ "Data", @@ -613,9 +611,9 @@ "showNode": true, "type": "ParseData" }, - "id": "ParseData-X7r7s", + "id": "ParseData-ZQpM3", "measured": { - "height": 263, + "height": 264, "width": 320 }, "position": { @@ -627,396 +625,7 @@ }, { "data": { - "id": "OpenAIModel-adSHw", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout" - ], - "frozen": false, - "icon": "OpenAI", - "legacy": false, - "lf_version": "1.1.5", - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - } - }, - "tool_mode": false - }, - "selected_output": "text_output", - "showNode": true, - "type": "OpenAIModel" - }, - "id": "OpenAIModel-adSHw", - "measured": { - "height": 537, - "width": 320 - }, - "position": { - "x": 2159.856153607566, - "y": 546.0283268474204 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Prompt-Vzk5z", + "id": "Prompt-Nc0MB", "node": { "base_classes": [ "Message" @@ -1155,9 +764,9 @@ "showNode": true, "type": "Prompt" }, - "id": "Prompt-Vzk5z", + "id": "Prompt-Nc0MB", "measured": { - "height": 365, + "height": 367, "width": 320 }, "position": { @@ -1169,7 +778,7 @@ }, { "data": { - "id": "ChatOutput-NbY9b", + "id": "ChatOutput-LTpUg", "node": { "base_classes": [ "Message" @@ -1457,9 +1066,9 @@ "showNode": true, "type": "ChatOutput" }, - "id": "ChatOutput-NbY9b", + "id": "ChatOutput-LTpUg", "measured": { - "height": 203, + "height": 204, "width": 320 }, "position": { @@ -1471,7 +1080,7 @@ }, { "data": { - "id": "ChatOutput-5pvPL", + "id": "ChatOutput-m5kak", "node": { "base_classes": [ "Message" @@ -1759,7 +1368,7 @@ "showNode": false, "type": "ChatOutput" }, - "id": "ChatOutput-5pvPL", + "id": "ChatOutput-m5kak", "measured": { "height": 48, "width": 192 @@ -1773,396 +1382,7 @@ }, { "data": { - "id": "OpenAIModel-A8LqG", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout" - ], - "frozen": false, - "icon": "OpenAI", - "legacy": false, - "lf_version": "1.1.5", - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - } - }, - "tool_mode": false - }, - "selected_output": "text_output", - "showNode": true, - "type": "OpenAIModel" - }, - "id": "OpenAIModel-A8LqG", - "measured": { - "height": 537, - "width": 320 - }, - "position": { - "x": 1668.2863585030223, - "y": 1394.531585772563 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "ChatOutput-paHng", + "id": "ChatOutput-SLRFg", "node": { "base_classes": [ "Message" @@ -2450,7 +1670,7 @@ "showNode": false, "type": "ChatOutput" }, - "id": "ChatOutput-paHng", + "id": "ChatOutput-SLRFg", "measured": { "height": 48, "width": 192 @@ -2464,7 +1684,7 @@ }, { "data": { - "id": "Prompt-iKEvN", + "id": "Prompt-qm57P", "node": { "base_classes": [ "Message" @@ -2627,9 +1847,9 @@ "showNode": true, "type": "Prompt" }, - "id": "Prompt-iKEvN", + "id": "Prompt-qm57P", "measured": { - "height": 417, + "height": 419, "width": 320 }, "position": { @@ -2641,7 +1861,7 @@ }, { "data": { - "id": "Memory-YN8aN", + "id": "Memory-W2jhq", "node": { "base_classes": [ "Data", @@ -2719,7 +1939,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from typing import Any, cast\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs.inputs import DropdownInput, HandleInput, IntInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.memory import aget_messages, astore_message\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\nfrom langflow.utils.component_utils import set_current_fields, set_field_display\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Stores or retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n default_keys = [\"mode\", \"memory\"]\n mode_config = {\n \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\"],\n }\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Retrieve\", \"Store\"],\n value=\"Retrieve\",\n info=\"Operation mode: Store messages or Retrieve messages.\",\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The chat message to be stored.\",\n tool_mode=True,\n dynamic=True,\n show=False,\n ),\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"sender_type\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender\",\n display_name=\"Sender\",\n info=\"The sender of the message. Might be Machine or User. \"\n \"If empty, the current sender parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n show=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n show=False,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n value=\"\",\n advanced=True,\n ),\n DropdownInput(\n name=\"order\",\n display_name=\"Order\",\n options=[\"Ascending\", \"Descending\"],\n value=\"Ascending\",\n info=\"Order of the messages.\",\n advanced=True,\n tool_mode=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {sender} or any other key in the message data.\",\n value=\"{sender_name}: {text}\",\n advanced=True,\n show=False,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Message\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True),\n Output(display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True),\n ]\n\n def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:\n \"\"\"Dynamically show only the relevant output based on the selected output type.\"\"\"\n if field_name == \"mode\":\n # Start with empty outputs\n frontend_node[\"outputs\"] = []\n if field_value == \"Store\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Stored Messages\",\n name=\"stored_messages\",\n method=\"store_message\",\n hidden=True,\n dynamic=True,\n )\n ]\n if field_value == \"Retrieve\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Messages\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True\n ),\n Output(\n display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True\n ),\n ]\n return frontend_node\n\n async def store_message(self) -> Message:\n message = Message(text=self.message) if isinstance(self.message, str) else self.message\n\n message.session_id = self.session_id or message.session_id\n message.sender = self.sender or message.sender or MESSAGE_SENDER_AI\n message.sender_name = self.sender_name or message.sender_name or MESSAGE_SENDER_NAME_AI\n\n stored_messages: list[Message] = []\n\n if self.memory:\n self.memory.session_id = message.session_id\n lc_message = message.to_lc_message()\n await self.memory.aadd_messages([lc_message])\n\n stored_messages = await self.memory.aget_messages() or []\n\n stored_messages = [Message.from_lc_message(m) for m in stored_messages] if stored_messages else []\n\n if message.sender:\n stored_messages = [m for m in stored_messages if m.sender == message.sender]\n else:\n await astore_message(message, flow_id=self.graph.flow_id)\n stored_messages = (\n await aget_messages(\n session_id=message.session_id, sender_name=message.sender_name, sender=message.sender\n )\n or []\n )\n\n if not stored_messages:\n msg = \"No messages were stored. Please ensure that the session ID and sender are properly set.\"\n raise ValueError(msg)\n\n stored_message = stored_messages[0]\n self.status = stored_message\n return stored_message\n\n async def retrieve_messages(self) -> Data:\n sender_type = self.sender_type\n sender_name = self.sender_name\n session_id = self.session_id\n n_messages = self.n_messages\n order = \"DESC\" if self.order == \"Descending\" else \"ASC\"\n\n if sender_type == \"Machine and User\":\n sender_type = None\n\n if self.memory and not hasattr(self.memory, \"aget_messages\"):\n memory_name = type(self.memory).__name__\n err_msg = f\"External Memory object ({memory_name}) must have 'aget_messages' method.\"\n raise AttributeError(err_msg)\n # Check if n_messages is None or 0\n if n_messages == 0:\n stored = []\n elif self.memory:\n # override session_id\n self.memory.session_id = session_id\n\n stored = await self.memory.aget_messages()\n # langchain memories are supposed to return messages in ascending order\n if order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender_type:\n expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n stored = await aget_messages(\n sender=sender_type,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n self.status = stored\n return cast(Data, stored)\n\n async def retrieve_messages_as_text(self) -> Message:\n stored_text = data_to_text(self.template, await self.retrieve_messages())\n self.status = stored_text\n return Message(text=stored_text)\n\n async def retrieve_messages_dataframe(self) -> DataFrame:\n \"\"\"Convert the retrieved messages into a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the message data.\n \"\"\"\n messages = await self.retrieve_messages()\n return DataFrame(messages)\n\n def update_build_config(\n self,\n build_config: dotdict,\n field_value: Any, # noqa: ARG002\n field_name: str | None = None, # noqa: ARG002\n ) -> dotdict:\n return set_current_fields(\n build_config=build_config,\n action_fields=self.mode_config,\n selected_action=build_config[\"mode\"][\"value\"],\n default_fields=self.default_keys,\n func=set_field_display,\n )\n" + "value": "from typing import Any, cast\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs.inputs import DropdownInput, HandleInput, IntInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.memory import aget_messages, astore_message\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\nfrom langflow.utils.component_utils import set_current_fields, set_field_display\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Stores or retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n default_keys = [\"mode\", \"memory\"]\n mode_config = {\n \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\"],\n }\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Retrieve\", \"Store\"],\n value=\"Retrieve\",\n info=\"Operation mode: Store messages or Retrieve messages.\",\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The chat message to be stored.\",\n tool_mode=True,\n dynamic=True,\n show=False,\n ),\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"sender_type\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender\",\n display_name=\"Sender\",\n info=\"The sender of the message. Might be Machine or User. \"\n \"If empty, the current sender parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n show=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n show=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 order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[-n_messages:] if order == \"ASC\" else stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender_type:\n expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n # 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:] if order == \"ASC\" else stored[: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", @@ -2952,21 +2172,22 @@ "showNode": true, "type": "Memory" }, - "id": "Memory-YN8aN", + "dragging": false, + "id": "Memory-W2jhq", "measured": { - "height": 217, + "height": 218, "width": 320 }, "position": { - "x": 685.5892616330983, - "y": 1365.244705292662 + "x": 441.48054213052956, + "y": 1316.8835438817757 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "ChatInput-xfgsq", + "id": "ChatInput-VajCb", "node": { "base_classes": [ "Message" @@ -3252,7 +2473,7 @@ "showNode": false, "type": "ChatInput" }, - "id": "ChatInput-xfgsq", + "id": "ChatInput-VajCb", "measured": { "height": 48, "width": 192 @@ -3266,7 +2487,7 @@ }, { "data": { - "id": "note-0oxqi", + "id": "note-X7VVg", "node": { "description": "### 💡 Add your Assembly AI API key and audio file here", "display_name": "", @@ -3279,10 +2500,10 @@ }, "dragging": false, "height": 324, - "id": "note-0oxqi", + "id": "note-X7VVg", "measured": { "height": 324, - "width": 455 + "width": 456 }, "position": { "x": 452.7834981529654, @@ -3295,7 +2516,7 @@ }, { "data": { - "id": "note-YC1zc", + "id": "note-KqIow", "node": { "description": "### 💡 Add your Assembly AI API key here", "display_name": "", @@ -3308,10 +2529,10 @@ }, "dragging": false, "height": 324, - "id": "note-YC1zc", + "id": "note-KqIow", "measured": { "height": 324, - "width": 364 + "width": 365 }, "position": { "x": 920.5426847894952, @@ -3324,7 +2545,7 @@ }, { "data": { - "id": "note-1sAEX", + "id": "note-CGltm", "node": { "description": "### 💡 Add your OpenAI API key here", "display_name": "", @@ -3337,10 +2558,10 @@ }, "dragging": false, "height": 324, - "id": "note-1sAEX", + "id": "note-CGltm", "measured": { "height": 324, - "width": 334 + "width": 335 }, "position": { "x": 2151.1746324575247, @@ -3353,7 +2574,7 @@ }, { "data": { - "id": "note-aqmS2", + "id": "note-Cy9Wp", "node": { "description": "### 💡 Add your OpenAI API key here", "display_name": "", @@ -3365,7 +2586,7 @@ "type": "note" }, "dragging": false, - "id": "note-aqmS2", + "id": "note-Cy9Wp", "measured": { "height": 324, "width": 324 @@ -3379,7 +2600,7 @@ }, { "data": { - "id": "AssemblyAITranscriptionJobCreator-hXp0S", + "id": "AssemblyAITranscriptionJobCreator-fAs7l", "node": { "base_classes": [ "Data" @@ -3697,9 +2918,9 @@ "type": "AssemblyAITranscriptionJobCreator" }, "dragging": false, - "id": "AssemblyAITranscriptionJobCreator-hXp0S", + "id": "AssemblyAITranscriptionJobCreator-fAs7l", "measured": { - "height": 341, + "height": 343, "width": 320 }, "position": { @@ -3711,7 +2932,7 @@ }, { "data": { - "id": "note-RCLbs", + "id": "note-tPJWf", "node": { "description": "# Meeting Summary Generator\n\nThis flow automatically transcribes and summarizes meetings by converting audio recordings into concise summaries using **AssemblyAI** and **OpenAI GPT-4**. \n\n## Prerequisites\n\n- **[AssemblyAI API Key](https://www.assemblyai.com/)**\n- **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quickstart\n\n1. Upload an audio file. Most common audio file formats are [supported](https://github.com/langflow-ai/langflow/blob/main/src/backend/base/langflow/components/assemblyai/assemblyai_start_transcript.py#L27).\n2. To run the summary generator flow, click **Playground**.\n\nThe flow transcribes the audio using **AssemblyAI**.\nThe transcript is formatted for AI processing.\nThe **GPT-4** model extracts key points and insights.\nThe summarized meeting details are displayed in a chat-friendly format.\n\n\n\n", "display_name": "", @@ -3722,10 +2943,10 @@ }, "dragging": false, "height": 612, - "id": "note-RCLbs", + "id": "note-tPJWf", "measured": { "height": 612, - "width": 549 + "width": 548 }, "position": { "x": -128.87171443390673, @@ -3738,7 +2959,7 @@ }, { "data": { - "id": "parser-uRyvX", + "id": "parser-YtYmK", "node": { "base_classes": [ "Message" @@ -3899,9 +3120,9 @@ "type": "parser" }, "dragging": false, - "id": "parser-uRyvX", + "id": "parser-YtYmK", "measured": { - "height": 359, + "height": 361, "width": 320 }, "position": { @@ -3913,7 +3134,7 @@ }, { "data": { - "id": "TypeConverterComponent-MzSbu", + "id": "TypeConverterComponent-E7sN7", "node": { "base_classes": [ "Message" @@ -4026,30 +3247,621 @@ "showNode": true, "type": "TypeConverterComponent" }, - "id": "TypeConverterComponent-MzSbu", + "dragging": false, + "id": "TypeConverterComponent-E7sN7", "measured": { - "height": 261, + "height": 262, "width": 320 }, "position": { - "x": 977.2392682107122, - "y": 1192.6380449385947 + "x": 818.3383092892287, + "y": 1236.393381453206 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-sdJZz", + "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": "OpenAI API Key", + "dynamic": false, + "info": "Model Provider API key", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "_input_type": "MultilineInput", + "advanced": 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 + }, + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-sdJZz", + "measured": { + "height": 451, + "width": 320 + }, + "position": { + "x": 2173.9107323014864, + "y": 602.584363428964 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-LzdL4", + "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": "OpenAI API Key", + "dynamic": false, + "info": "Model Provider API key", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "_input_type": "MultilineInput", + "advanced": 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 + }, + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-LzdL4", + "measured": { + "height": 451, + "width": 320 + }, + "position": { + "x": 1682.4309619697785, + "y": 1466.0777133523027 }, "selected": true, "type": "genericNode" } ], "viewport": { - "x": -131.07372789550516, - "y": -274.4531542699592, - "zoom": 0.5495826307500584 + "x": -517.5818469117869, + "y": -364.65252188569104, + "zoom": 0.637519084679716 } }, "description": "An AI-powered meeting summary generator that transcribes and summarizes meetings using AssemblyAI and OpenAI for quick insights.", "endpoint_name": null, - "id": "f05e8cbd-e83e-4c66-9c89-29dd57c72739", + "id": "dd491f01-5b33-449a-9a03-9a840c70cf0f", "is_component": false, - "last_tested_version": "1.4.2", + "last_tested_version": "1.4.3", "name": "Meeting Summary", "tags": [ "chatbots", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json index c40c9c1f6..79bb100e8 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json @@ -1034,7 +1034,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from typing import Any, cast\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs.inputs import DropdownInput, HandleInput, IntInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.memory import aget_messages, astore_message\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\nfrom langflow.utils.component_utils import set_current_fields, set_field_display\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Stores or retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n default_keys = [\"mode\", \"memory\"]\n mode_config = {\n \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\"],\n }\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Retrieve\", \"Store\"],\n value=\"Retrieve\",\n info=\"Operation mode: Store messages or Retrieve messages.\",\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The chat message to be stored.\",\n tool_mode=True,\n dynamic=True,\n show=False,\n ),\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"sender_type\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender\",\n display_name=\"Sender\",\n info=\"The sender of the message. Might be Machine or User. \"\n \"If empty, the current sender parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n show=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n show=False,\n ),\n MessageTextInput(\n name=\"session_id\",\n display_name=\"Session ID\",\n info=\"The session ID of the chat. If empty, the current session ID parameter will be used.\",\n value=\"\",\n advanced=True,\n ),\n DropdownInput(\n name=\"order\",\n display_name=\"Order\",\n options=[\"Ascending\", \"Descending\"],\n value=\"Ascending\",\n info=\"Order of the messages.\",\n advanced=True,\n tool_mode=True,\n required=True,\n ),\n MultilineInput(\n name=\"template\",\n display_name=\"Template\",\n info=\"The template to use for formatting the data. \"\n \"It can contain the keys {text}, {sender} or any other key in the message data.\",\n value=\"{sender_name}: {text}\",\n advanced=True,\n show=False,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Message\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True),\n Output(display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True),\n ]\n\n def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:\n \"\"\"Dynamically show only the relevant output based on the selected output type.\"\"\"\n if field_name == \"mode\":\n # Start with empty outputs\n frontend_node[\"outputs\"] = []\n if field_value == \"Store\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Stored Messages\",\n name=\"stored_messages\",\n method=\"store_message\",\n hidden=True,\n dynamic=True,\n )\n ]\n if field_value == \"Retrieve\":\n frontend_node[\"outputs\"] = [\n Output(\n display_name=\"Messages\", name=\"messages_text\", method=\"retrieve_messages_as_text\", dynamic=True\n ),\n Output(\n display_name=\"Dataframe\", name=\"dataframe\", method=\"retrieve_messages_dataframe\", dynamic=True\n ),\n ]\n return frontend_node\n\n async def store_message(self) -> Message:\n message = Message(text=self.message) if isinstance(self.message, str) else self.message\n\n message.session_id = self.session_id or message.session_id\n message.sender = self.sender or message.sender or MESSAGE_SENDER_AI\n message.sender_name = self.sender_name or message.sender_name or MESSAGE_SENDER_NAME_AI\n\n stored_messages: list[Message] = []\n\n if self.memory:\n self.memory.session_id = message.session_id\n lc_message = message.to_lc_message()\n await self.memory.aadd_messages([lc_message])\n\n stored_messages = await self.memory.aget_messages() or []\n\n stored_messages = [Message.from_lc_message(m) for m in stored_messages] if stored_messages else []\n\n if message.sender:\n stored_messages = [m for m in stored_messages if m.sender == message.sender]\n else:\n await astore_message(message, flow_id=self.graph.flow_id)\n stored_messages = (\n await aget_messages(\n session_id=message.session_id, sender_name=message.sender_name, sender=message.sender\n )\n or []\n )\n\n if not stored_messages:\n msg = \"No messages were stored. Please ensure that the session ID and sender are properly set.\"\n raise ValueError(msg)\n\n stored_message = stored_messages[0]\n self.status = stored_message\n return stored_message\n\n async def retrieve_messages(self) -> Data:\n sender_type = self.sender_type\n sender_name = self.sender_name\n session_id = self.session_id\n n_messages = self.n_messages\n order = \"DESC\" if self.order == \"Descending\" else \"ASC\"\n\n if sender_type == \"Machine and User\":\n sender_type = None\n\n if self.memory and not hasattr(self.memory, \"aget_messages\"):\n memory_name = type(self.memory).__name__\n err_msg = f\"External Memory object ({memory_name}) must have 'aget_messages' method.\"\n raise AttributeError(err_msg)\n # Check if n_messages is None or 0\n if n_messages == 0:\n stored = []\n elif self.memory:\n # override session_id\n self.memory.session_id = session_id\n\n stored = await self.memory.aget_messages()\n # langchain memories are supposed to return messages in ascending order\n if order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender_type:\n expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n stored = await aget_messages(\n sender=sender_type,\n sender_name=sender_name,\n session_id=session_id,\n limit=n_messages,\n order=order,\n )\n self.status = stored\n return cast(Data, stored)\n\n async def retrieve_messages_as_text(self) -> Message:\n stored_text = data_to_text(self.template, await self.retrieve_messages())\n self.status = stored_text\n return Message(text=stored_text)\n\n async def retrieve_messages_dataframe(self) -> DataFrame:\n \"\"\"Convert the retrieved messages into a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the message data.\n \"\"\"\n messages = await self.retrieve_messages()\n return DataFrame(messages)\n\n def update_build_config(\n self,\n build_config: dotdict,\n field_value: Any, # noqa: ARG002\n field_name: str | None = None, # noqa: ARG002\n ) -> dotdict:\n return set_current_fields(\n build_config=build_config,\n action_fields=self.mode_config,\n selected_action=build_config[\"mode\"][\"value\"],\n default_fields=self.default_keys,\n func=set_field_display,\n )\n" + "value": "from typing import Any, cast\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.helpers.data import data_to_text\nfrom langflow.inputs.inputs import DropdownInput, HandleInput, IntInput, MessageTextInput, MultilineInput, TabInput\nfrom langflow.memory import aget_messages, astore_message\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\nfrom langflow.template.field.base import Output\nfrom langflow.utils.component_utils import set_current_fields, set_field_display\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSAGE_SENDER_USER\n\n\nclass MemoryComponent(Component):\n display_name = \"Message History\"\n description = \"Stores or retrieves stored chat messages from Langflow tables or an external memory.\"\n icon = \"message-square-more\"\n name = \"Memory\"\n default_keys = [\"mode\", \"memory\"]\n mode_config = {\n \"Store\": [\"message\", \"memory\", \"sender\", \"sender_name\", \"session_id\"],\n \"Retrieve\": [\"n_messages\", \"order\", \"template\", \"memory\"],\n }\n\n inputs = [\n TabInput(\n name=\"mode\",\n display_name=\"Mode\",\n options=[\"Retrieve\", \"Store\"],\n value=\"Retrieve\",\n info=\"Operation mode: Store messages or Retrieve messages.\",\n real_time_refresh=True,\n ),\n MessageTextInput(\n name=\"message\",\n display_name=\"Message\",\n info=\"The chat message to be stored.\",\n tool_mode=True,\n dynamic=True,\n show=False,\n ),\n HandleInput(\n name=\"memory\",\n display_name=\"External Memory\",\n input_types=[\"Memory\"],\n info=\"Retrieve messages from an external memory. If empty, it will use the Langflow tables.\",\n advanced=True,\n ),\n DropdownInput(\n name=\"sender_type\",\n display_name=\"Sender Type\",\n options=[MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, \"Machine and User\"],\n value=\"Machine and User\",\n info=\"Filter by sender type.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender\",\n display_name=\"Sender\",\n info=\"The sender of the message. Might be Machine or User. \"\n \"If empty, the current sender parameter will be used.\",\n advanced=True,\n ),\n MessageTextInput(\n name=\"sender_name\",\n display_name=\"Sender Name\",\n info=\"Filter by sender name.\",\n advanced=True,\n show=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Messages\",\n value=100,\n info=\"Number of messages to retrieve.\",\n advanced=True,\n show=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 order == \"DESC\":\n stored = stored[::-1]\n if n_messages:\n stored = stored[-n_messages:] if order == \"ASC\" else stored[:n_messages]\n stored = [Message.from_lc_message(m) for m in stored]\n if sender_type:\n expected_type = MESSAGE_SENDER_AI if sender_type == MESSAGE_SENDER_AI else MESSAGE_SENDER_USER\n stored = [m for m in stored if m.type == expected_type]\n else:\n # 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:] if order == \"ASC\" else stored[: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", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json index 0297c98f8..21d0f890b 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json @@ -1,99 +1,13 @@ { "data": { "edges": [ - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "AgentQL", - "id": "AgentQL-mAUuI", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-MtFB7", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-AgentQL-mAUuI{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-mAUuIœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-MtFB7{œfieldNameœ:œtoolsœ,œidœ:œAgent-MtFB7œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "AgentQL-mAUuI", - "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-mAUuIœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-MtFB7", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-MtFB7œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-l2zGd", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-MtFB7", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-l2zGd{œdataTypeœ:œChatInputœ,œidœ:œChatInput-l2zGdœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-MtFB7{œfieldNameœ:œinput_valueœ,œidœ:œAgent-MtFB7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-l2zGd", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-l2zGdœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-MtFB7", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-MtFB7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Agent", - "id": "Agent-MtFB7", - "name": "response", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "ChatOutput-ZC7ao", - "inputTypes": [ - "Data", - "DataFrame", - "Message" - ], - "type": "other" - } - }, - "id": "reactflow__edge-Agent-MtFB7{œdataTypeœ:œAgentœ,œidœ:œAgent-MtFB7œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-ZC7ao{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-ZC7aoœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", - "selected": false, - "source": "Agent-MtFB7", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-MtFB7œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-ZC7ao", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-ZC7aoœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" - }, { "animated": false, "className": "", "data": { "sourceHandle": { "dataType": "ChatOutput", - "id": "ChatOutput-ZC7ao", + "id": "ChatOutput-C4HEa", "name": "message", "output_types": [ "Message" @@ -101,7 +15,7 @@ }, "targetHandle": { "fieldName": "input", - "id": "SaveToFile-PIe7f", + "id": "SaveToFile-ZGqsp", "inputTypes": [ "Data", "DataFrame", @@ -110,18 +24,95 @@ "type": "other" } }, - "id": "xy-edge__ChatOutput-ZC7ao{œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-ZC7aoœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-SaveToFile-PIe7f{œfieldNameœ:œinputœ,œidœ:œSaveToFile-PIe7fœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-ChatOutput-C4HEa{œdataTypeœ:œChatOutputœ,œidœ:œChatOutput-C4HEaœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-SaveToFile-ZGqsp{œfieldNameœ:œinputœ,œidœ:œSaveToFile-ZGqspœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "ChatOutput-ZC7ao", - "sourceHandle": "{œdataTypeœ: œChatOutputœ, œidœ: œChatOutput-ZC7aoœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "SaveToFile-PIe7f", - "targetHandle": "{œfieldNameœ: œinputœ, œidœ: œSaveToFile-PIe7fœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "ChatOutput-C4HEa", + "sourceHandle": "{œdataTypeœ: œChatOutputœ, œidœ: œChatOutput-C4HEaœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "SaveToFile-ZGqsp", + "targetHandle": "{œfieldNameœ: œinputœ, œidœ: œSaveToFile-ZGqspœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "AgentQL", + "id": "AgentQL-0NT3t", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-2FQMc", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__AgentQL-0NT3t{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-0NT3tœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-2FQMc{œfieldNameœ:œtoolsœ,œidœ:œAgent-2FQMcœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "source": "AgentQL-0NT3t", + "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-0NT3tœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-2FQMc", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-2FQMcœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-lC5SH", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-2FQMc", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__ChatInput-lC5SH{œdataTypeœ:œChatInputœ,œidœ:œChatInput-lC5SHœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-2FQMc{œfieldNameœ:œinput_valueœ,œidœ:œAgent-2FQMcœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "ChatInput-lC5SH", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-lC5SHœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-2FQMc", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-2FQMcœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Agent", + "id": "Agent-2FQMc", + "name": "response", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "ChatOutput-C4HEa", + "inputTypes": [ + "Data", + "DataFrame", + "Message" + ], + "type": "other" + } + }, + "id": "xy-edge__Agent-2FQMc{œdataTypeœ:œAgentœ,œidœ:œAgent-2FQMcœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-C4HEa{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-C4HEaœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "source": "Agent-2FQMc", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-2FQMcœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-C4HEa", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-C4HEaœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "note-QUpTh", + "id": "note-SLgQS", "node": { "description": "### 💡 Add your OpenAI API key here", "display_name": "", @@ -133,7 +124,7 @@ "type": "note" }, "dragging": false, - "id": "note-QUpTh", + "id": "note-SLgQS", "measured": { "height": 324, "width": 324 @@ -147,7 +138,7 @@ }, { "data": { - "id": "note-e9QOB", + "id": "note-HZbAs", "node": { "description": "### 💡 Add your AgentQL API key here", "display_name": "", @@ -160,7 +151,7 @@ }, "dragging": false, "height": 346, - "id": "note-e9QOB", + "id": "note-HZbAs", "measured": { "height": 346, "width": 324 @@ -176,7 +167,7 @@ "data": { "description": "Uses AgentQL API to extract structured data from a given URL.", "display_name": "AgentQL Query Data", - "id": "AgentQL-mAUuI", + "id": "AgentQL-0NT3t", "node": { "base_classes": [ "Data" @@ -236,7 +227,7 @@ "dynamic": false, "info": "Your AgentQL API key from dev.agentql.com", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -244,7 +235,7 @@ "show": true, "title_case": false, "type": "str", - "value": "AGENTQL_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -514,7 +505,7 @@ "type": "AgentQL" }, "dragging": false, - "id": "AgentQL-mAUuI", + "id": "AgentQL-0NT3t", "measured": { "height": 316, "width": 320 @@ -528,7 +519,7 @@ }, { "data": { - "id": "ChatInput-l2zGd", + "id": "ChatInput-lC5SH", "node": { "base_classes": [ "Message" @@ -828,7 +819,7 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-l2zGd", + "id": "ChatInput-lC5SH", "measured": { "height": 48, "width": 192 @@ -842,767 +833,7 @@ }, { "data": { - "id": "Agent-MtFB7", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "list_add_label": "Add More", - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Anthropic", - "Google Generative AI", - "Groq", - "OpenAI", - "Custom" - ], - "options_metadata": [ - { - "icon": "Amazon" - }, - { - "icon": "Anthropic" - }, - { - "icon": "Azure" - }, - { - "icon": "GoogleGenerativeAI" - }, - { - "icon": "Groq" - }, - { - "icon": "NVIDIA" - }, - { - "icon": "OpenAI" - }, - { - "icon": "SambaNova" - }, - { - "icon": "brain" - } - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "OPENAI_API_KEY" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "list_add_label": "Add More", - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "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": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "list_add_label": "Add More", - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": false, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "n_messages": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Number of Messages", - "dynamic": false, - "info": "Number of messages to retrieve.", - "list": false, - "list_add_label": "Add More", - "name": "n_messages", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "options_metadata": [], - "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, - "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": "" - }, - "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, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a helpful content writer researching news and social posts for our company.\n\nCreate a new JSON file and insert the extracted data into that file.\n\nYou will use the AgentQL tool when getting content from URLs. Be sure to get the URL, author, content, and publish date. Here's how to write an AgentQL query:\n\nThe AgentQL query serves as the building block of your script. This guide shows you how AgentQL's query structure works and how to write a valid query.\n\n### Single term query\n\nA **single term query** enables you to retrieve a single element on the webpage. Here is an example of how you can write a single term query to retrieve a search box.\n\n```AgentQL\n{\n search_box\n}\n```\n\n### List term query\n\nA **list term query** enables you to retrieve a list of similar elements on the webpage. Here is an example of how you can write a list term query to retrieve a list of prices of apples.\n\n```AgentQL\n{\n apple_price[]\n}\n```\n\nYou can also specify the exact field you want to return in the list. Here is an example of how you can specify that you want the name and price from the list of products.\n\n```AgentQL\n{\n products[] {\n name\n price(integer)\n }\n}\n```\n\n### Combining single term queries and list term queries\n\nYou can query for both **single terms** and **list terms** by combining the preceding formats.\n\n```AgentQL\n{\n author\n date_of_birth\n book_titles[]\n}\n```\n\n### Giving context to queries\n\nThere two main ways you can provide additional context to your queries.\n\n#### Structural context\n\nYou can nest queries within parent containers to indicate that your target web element is in a particular section of the webpage.\n\n```AgentQL\n{\n footer {\n social_media_links[]\n }\n}\n```\n\n#### Semantic context\n\nYou can also provide a short description within parentheses to guide AgentQL in locating the right element(s).\n\n```AgentQL\n{\n footer {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n }\n}\n```\n\n### Syntax guidelines\n\nEnclose all AgentQL query terms within curly braces `{}`. The following query structure isn't valid because the term \"social_media_links\" is wrongly enclosed within parenthesis`()`.\n\n```AgentQL\n( # Should be {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n) # Should be }\n```\n\nYou can't include new lines in your semantic context. The following query structure isn't valid because the semantic context isn't contained within one line.\n\n```AgentQL\n{\n social_media_links(The icons that lead\n to Facebook, Snapchat, etc.)[]\n}\n```" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "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, - "list_add_label": "Add More", - "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}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "list_add_label": "Add More", - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "showNode": true, - "type": "Agent" - }, - "dragging": false, - "id": "Agent-MtFB7", - "measured": { - "height": 593, - "width": 320 - }, - "position": { - "x": 1176.7234802624862, - "y": 190.59802023099996 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "note-lghpM", + "id": "note-VDjrw", "node": { "description": "# News Aggregator\n\nThis flow extracts structured data from a URL and saves it into a JSON file.\n\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Click **Playground** and enter a question.\n\nThe **Agent** component populates the **AgentQL** component's **URL** and **Query** fields, and returns a structured response to your question. Then the extracted data is saved into a JSON file `news-aggregated.json`, which can be found in your current project directory.", "display_name": "", @@ -1614,10 +845,10 @@ "type": "note" }, "dragging": false, - "id": "note-lghpM", + "id": "note-VDjrw", "measured": { "height": 696, - "width": 325 + "width": 575 }, "position": { "x": 385.05237560524864, @@ -1628,7 +859,7 @@ }, { "data": { - "id": "ChatOutput-ZC7ao", + "id": "ChatOutput-C4HEa", "node": { "base_classes": [ "Message" @@ -1923,7 +1154,7 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-ZC7ao", + "id": "ChatOutput-C4HEa", "measured": { "height": 48, "width": 192 @@ -1937,7 +1168,7 @@ }, { "data": { - "id": "SaveToFile-PIe7f", + "id": "SaveToFile-ZGqsp", "node": { "base_classes": [ "Message" @@ -2073,7 +1304,7 @@ "type": "SaveToFile" }, "dragging": false, - "id": "SaveToFile-PIe7f", + "id": "SaveToFile-ZGqsp", "measured": { "height": 248, "width": 320 @@ -2084,17 +1315,561 @@ }, "selected": false, "type": "genericNode" + }, + { + "data": { + "id": "Agent-2FQMc", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "category": "agents", + "conditional_paths": [], + "custom_fields": {}, + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "Agent", + "documentation": "", + "edited": false, + "field_order": [ + "agent_llm", + "max_tokens", + "model_kwargs", + "json_mode", + "model_name", + "openai_api_base", + "api_key", + "temperature", + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" + ], + "frozen": false, + "icon": "bot", + "key": "Agent", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Response", + "group_outputs": false, + "method": "message_response", + "name": "response", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 1.1732828199964098e-19, + "template": { + "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "input_value": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input provided by the user for the agent to process.", + "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": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "json_mode": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "JSON Mode", + "dynamic": false, + "info": "If True, it will output JSON regardless of passing a schema.", + "list": false, + "list_add_label": "Add More", + "name": "json_mode", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, + "max_retries": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "The maximum number of retries to make when generating.", + "list": false, + "list_add_label": "Add More", + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_tokens": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "list_add_label": "Add More", + "name": "max_tokens", + "placeholder": "", + "range_spec": { + "max": 128000, + "min": 0, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "Additional keyword arguments to pass to the model.", + "list": false, + "list_add_label": "Add More", + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": true, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo", + "o1" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "openai_api_base": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "seed": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "list_add_label": "Add More", + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "system_prompt": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Agent Instructions", + "dynamic": false, + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_prompt", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "You are a helpful content writer researching news and social posts for our company.\n\nCreate a new JSON file and insert the extracted data into that file.\n\nYou will use the AgentQL tool when getting content from URLs. Be sure to get the URL, author, content, and publish date. Here's how to write an AgentQL query:\n\nThe AgentQL query serves as the building block of your script. This guide shows you how AgentQL's query structure works and how to write a valid query.\n\n### Single term query\n\nA **single term query** enables you to retrieve a single element on the webpage. Here is an example of how you can write a single term query to retrieve a search box.\n\n```AgentQL\n{\n search_box\n}\n```\n\n### List term query\n\nA **list term query** enables you to retrieve a list of similar elements on the webpage. Here is an example of how you can write a list term query to retrieve a list of prices of apples.\n\n```AgentQL\n{\n apple_price[]\n}\n```\n\nYou can also specify the exact field you want to return in the list. Here is an example of how you can specify that you want the name and price from the list of products.\n\n```AgentQL\n{\n products[] {\n name\n price(integer)\n }\n}\n```\n\n### Combining single term queries and list term queries\n\nYou can query for both **single terms** and **list terms** by combining the preceding formats.\n\n```AgentQL\n{\n author\n date_of_birth\n book_titles[]\n}\n```\n\n### Giving context to queries\n\nThere two main ways you can provide additional context to your queries.\n\n#### Structural context\n\nYou can nest queries within parent containers to indicate that your target web element is in a particular section of the webpage.\n\n```AgentQL\n{\n footer {\n social_media_links[]\n }\n}\n```\n\n#### Semantic context\n\nYou can also provide a short description within parentheses to guide AgentQL in locating the right element(s).\n\n```AgentQL\n{\n footer {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n }\n}\n```\n\n### Syntax guidelines\n\nEnclose all AgentQL query terms within curly braces `{}`. The following query structure isn't valid because the term \"social_media_links\" is wrongly enclosed within parenthesis`()`.\n\n```AgentQL\n( # Should be {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n) # Should be }\n```\n\nYou can't include new lines in your semantic context. The following query structure isn't valid because the semantic context isn't contained within one line.\n\n```AgentQL\n{\n social_media_links(The icons that lead\n to Facebook, Snapchat, etc.)[]\n}\n```" + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "The timeout for requests to OpenAI completion API.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "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": "Agent" + }, + "dragging": false, + "id": "Agent-2FQMc", + "measured": { + "height": 594, + "width": 320 + }, + "position": { + "x": 1151.0943181682178, + "y": 225.0272050437212 + }, + "selected": false, + "type": "genericNode" } ], "viewport": { - "x": -259.1169460892288, - "y": 69.5397109756077, - "zoom": 0.787209650668357 + "x": 67.66904931759336, + "y": 380.21327964833256, + "zoom": 0.5689930627938247 } }, "description": "Extracts data and information from webpages.", "endpoint_name": null, - "id": "b5548b67-c370-4931-83f5-e3b934c3b116", + "id": "cd41ad0c-90bd-410b-8efe-5141e5e57e00", "is_component": false, "last_tested_version": "1.4.3", "name": "News Aggregator", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json index 31530b028..99e3d4efd 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json @@ -2,11 +2,10 @@ "data": { "edges": [ { - "animated": false, "data": { "sourceHandle": { "dataType": "APIRequest", - "id": "APIRequest-Yr0ij", + "id": "APIRequest-omX8o", "name": "component_as_tool", "output_types": [ "Tool" @@ -14,26 +13,24 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-iU8sJ", + "id": "Agent-R27kt", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__APIRequest-Yr0ij{œdataTypeœ:œAPIRequestœ,œidœ:œAPIRequest-Yr0ijœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-iU8sJ{œfieldNameœ:œtoolsœ,œidœ:œAgent-iU8sJœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "APIRequest-Yr0ij", - "sourceHandle": "{œdataTypeœ: œAPIRequestœ, œidœ: œAPIRequest-Yr0ijœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-iU8sJ", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-iU8sJœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "id": "xy-edge__APIRequest-omX8o{œdataTypeœ:œAPIRequestœ,œidœ:œAPIRequest-omX8oœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-R27kt{œfieldNameœ:œtoolsœ,œidœ:œAgent-R27ktœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "source": "APIRequest-omX8o", + "sourceHandle": "{œdataTypeœ: œAPIRequestœ, œidœ: œAPIRequest-omX8oœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-R27kt", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-R27ktœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { - "animated": false, "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-ZNO2E", + "id": "ChatInput-JJmqy", "name": "message", "output_types": [ "Message" @@ -41,26 +38,24 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-iU8sJ", + "id": "Agent-R27kt", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "xy-edge__ChatInput-ZNO2E{œdataTypeœ:œChatInputœ,œidœ:œChatInput-ZNO2Eœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-iU8sJ{œfieldNameœ:œinput_valueœ,œidœ:œAgent-iU8sJœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-ZNO2E", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-ZNO2Eœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-iU8sJ", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-iU8sJœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "id": "xy-edge__ChatInput-JJmqy{œdataTypeœ:œChatInputœ,œidœ:œChatInput-JJmqyœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-R27kt{œfieldNameœ:œinput_valueœ,œidœ:œAgent-R27ktœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "ChatInput-JJmqy", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-JJmqyœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-R27kt", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-R27ktœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { - "animated": false, "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-iU8sJ", + "id": "Agent-R27kt", "name": "response", "output_types": [ "Message" @@ -68,7 +63,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-79PxR", + "id": "ChatOutput-lbrgJ", "inputTypes": [ "Data", "DataFrame", @@ -77,18 +72,17 @@ "type": "str" } }, - "id": "xy-edge__Agent-iU8sJ{œdataTypeœ:œAgentœ,œidœ:œAgent-iU8sJœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-79PxR{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-79PxRœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Agent-iU8sJ", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-iU8sJœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-79PxR", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-79PxRœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "id": "xy-edge__Agent-R27kt{œdataTypeœ:œAgentœ,œidœ:œAgent-R27ktœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-lbrgJ{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-lbrgJœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "source": "Agent-R27kt", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-R27ktœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-lbrgJ", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-lbrgJœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-ZNO2E", + "id": "ChatInput-JJmqy", "node": { "base_classes": [ "Message" @@ -388,9 +382,9 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-ZNO2E", + "id": "ChatInput-JJmqy", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -402,7 +396,7 @@ }, { "data": { - "id": "ChatOutput-79PxR", + "id": "ChatOutput-lbrgJ", "node": { "base_classes": [ "Message" @@ -700,9 +694,9 @@ "showNode": false, "type": "ChatOutput" }, - "id": "ChatOutput-79PxR", + "id": "ChatOutput-lbrgJ", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -714,7 +708,7 @@ }, { "data": { - "id": "note-5GFoW", + "id": "note-avilJ", "node": { "description": "## Open the playground and ask anything about a Pokémon! ⚡ 🐹", "display_name": "", @@ -727,10 +721,10 @@ }, "dragging": false, "height": 324, - "id": "note-5GFoW", + "id": "note-avilJ", "measured": { "height": 324, - "width": 390 + "width": 391 }, "position": { "x": 972.3620941029305, @@ -743,7 +737,7 @@ }, { "data": { - "id": "note-4muEO", + "id": "note-g8DQ7", "node": { "description": "# Pokédex Agent\n\nCollect research on Pokémon with a specialized **Agent** and the Pokédex API.\n\n## Prerequisites\n\n* An [OpenAI API key](https://platform.openai.com/)\n\n## Quickstart\n\n1. Paste your OpenAI API key in the **Agent** component.\n2. Click **Playground** and ask about your favorite Pokémon.\nThe **Agent** queries the Pokedex API and returns a formatted entry.", "display_name": "", @@ -754,10 +748,10 @@ }, "dragging": false, "height": 543, - "id": "note-4muEO", + "id": "note-g8DQ7", "measured": { "height": 543, - "width": 349 + "width": 348 }, "position": { "x": -364.79357624384227, @@ -770,7 +764,7 @@ }, { "data": { - "id": "note-8KPfY", + "id": "note-Y6FRA", "node": { "description": "### 💡 Add your OpenAI API key here", "display_name": "", @@ -783,10 +777,10 @@ }, "dragging": false, "height": 324, - "id": "note-8KPfY", + "id": "note-Y6FRA", "measured": { "height": 324, - "width": 334 + "width": 335 }, "position": { "x": 572.2283687381639, @@ -799,7 +793,7 @@ }, { "data": { - "id": "APIRequest-Yr0ij", + "id": "APIRequest-omX8o", "node": { "base_classes": [ "Data", @@ -838,6 +832,7 @@ "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": null, "method": "to_toolkit", "name": "component_as_tool", @@ -1167,56 +1162,27 @@ "value": [ { "args": { - "curl": { + "curl_input": { "default": "", "description": "Paste a curl command to populate the fields. This will fill in the dictionary fields for headers and body.", - "title": "Curl", + "title": "Curl Input", "type": "string" }, - "urls": { + "url_input": { "default": "", - "description": "Enter one or more URLs, separated by commas.", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" - } - }, - "description": "APIRequest. make_requests() - Make HTTP requests using URLs or cURL commands.", - "display_description": "APIRequest. make_requests() - Make HTTP requests using URLs or cURL commands.", - "display_name": "make_requests", - "name": "make_requests", - "status": true, - "tags": [ - "make_requests" - ] - }, - { - "args": { - "curl": { - "default": "", - "description": "Paste a curl command to populate the fields. This will fill in the dictionary fields for headers and body.", - "title": "Curl", + "description": "Enter the URL for the request.", + "title": "Url Input", "type": "string" - }, - "urls": { - "default": "", - "description": "Enter one or more URLs, separated by commas.", - "items": { - "type": "string" - }, - "title": "Urls", - "type": "array" } }, - "description": "APIRequest. as_dataframe() - Make HTTP requests using URLs or cURL commands.", - "display_description": "APIRequest. as_dataframe() - Make HTTP requests using URLs or cURL commands.", - "display_name": "as_dataframe", - "name": "as_dataframe", + "description": "Make HTTP requests using URL or cURL commands.", + "display_description": "Make HTTP requests using URL or cURL commands.", + "display_name": "make_api_request", + "name": "make_api_request", + "readonly": false, "status": true, "tags": [ - "as_dataframe" + "make_api_request" ] } ] @@ -1252,9 +1218,9 @@ "type": "APIRequest" }, "dragging": false, - "id": "APIRequest-Yr0ij", + "id": "APIRequest-omX8o", "measured": { - "height": 372, + "height": 381, "width": 320 }, "position": { @@ -1266,7 +1232,7 @@ }, { "data": { - "id": "Agent-iU8sJ", + "id": "Agent-R27kt", "node": { "base_classes": [ "Message" @@ -1292,19 +1258,13 @@ "max_retries", "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, @@ -1319,8 +1279,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1330,7 +1293,7 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, + "score": 5.283996070936036e-7, "template": { "_type": "Component", "add_current_date_tool": { @@ -1428,15 +1391,16 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1454,7 +1418,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1575,70 +1539,6 @@ "type": "int", "value": "" }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -1689,14 +1589,14 @@ "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4.1" + "value": "gpt-4o" }, "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, "list_add_label": "Add More", "name": "n_messages", @@ -1728,30 +1628,6 @@ "type": "str", "value": "" }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, "seed": { "_input_type": "IntInput", "advanced": true, @@ -1770,102 +1646,6 @@ "type": "int", "value": 1 }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "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" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "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": "" - }, - "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, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, @@ -1919,31 +1699,6 @@ "type": "slider", "value": 0.1 }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "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}" - }, "timeout": { "_input_type": "IntInput", "advanced": true, @@ -2003,35 +1758,34 @@ }, "tool_mode": false }, - "selected_output": "response", "showNode": true, "type": "Agent" }, "dragging": false, - "id": "Agent-iU8sJ", + "id": "Agent-R27kt", "measured": { - "height": 624, + "height": 594, "width": 320 }, "position": { - "x": 553.2856156382643, - "y": -292.8049710393936 + "x": 555.1330402838014, + "y": -276.19262986280614 }, - "selected": true, + "selected": false, "type": "genericNode" } ], "viewport": { - "x": 293.61191901823486, - "y": 568.7214260270939, - "zoom": 0.6513599320055071 + "x": 344.37556379203, + "y": 595.7637964596969, + "zoom": 0.7631043470073409 } }, "description": "Research Pokémon with a specialized Agent and the Pokédex API.", "endpoint_name": null, - "id": "3eb87d27-6b74-4936-895f-5c3eae452456", + "id": "618225b9-a6b6-473b-98b8-b012eafb5193", "is_component": false, - "last_tested_version": "1.3.4", + "last_tested_version": "1.4.3", "name": "Pokédex Agent", "tags": [ "agents" diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json index 47ec12207..d17712f1b 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json @@ -2,11 +2,10 @@ "data": { "edges": [ { - "className": "", "data": { "sourceHandle": { "dataType": "AgentQL", - "id": "AgentQL-fgRow", + "id": "AgentQL-qCiM5", "name": "component_as_tool", "output_types": [ "Tool" @@ -14,25 +13,24 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-ghqeP", + "id": "Agent-03SGo", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__AgentQL-fgRow{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-fgRowœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-ghqeP{œfieldNameœ:œtoolsœ,œidœ:œAgent-ghqePœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "source": "AgentQL-fgRow", - "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-fgRowœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-ghqeP", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-ghqePœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "id": "xy-edge__AgentQL-qCiM5{œdataTypeœ:œAgentQLœ,œidœ:œAgentQL-qCiM5œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-03SGo{œfieldNameœ:œtoolsœ,œidœ:œAgent-03SGoœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "source": "AgentQL-qCiM5", + "sourceHandle": "{œdataTypeœ: œAgentQLœ, œidœ: œAgentQL-qCiM5œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-03SGo", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-03SGoœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "TavilySearchComponent", - "id": "TavilySearchComponent-L8PP0", + "id": "TavilySearchComponent-nWDnP", "name": "component_as_tool", "output_types": [ "Tool" @@ -40,25 +38,24 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-ghqeP", + "id": "Agent-03SGo", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__TavilySearchComponent-L8PP0{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-L8PP0œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-ghqeP{œfieldNameœ:œtoolsœ,œidœ:œAgent-ghqePœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "source": "TavilySearchComponent-L8PP0", - "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-L8PP0œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-ghqeP", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-ghqePœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "id": "xy-edge__TavilySearchComponent-nWDnP{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-nWDnPœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-03SGo{œfieldNameœ:œtoolsœ,œidœ:œAgent-03SGoœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "source": "TavilySearchComponent-nWDnP", + "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-nWDnPœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-03SGo", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-03SGoœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-IrBdK", + "id": "ChatInput-fJHKg", "name": "message", "output_types": [ "Message" @@ -66,25 +63,24 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-ghqeP", + "id": "Agent-03SGo", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "xy-edge__ChatInput-IrBdK{œdataTypeœ:œChatInputœ,œidœ:œChatInput-IrBdKœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-ghqeP{œfieldNameœ:œinput_valueœ,œidœ:œAgent-ghqePœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "ChatInput-IrBdK", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-IrBdKœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-ghqeP", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-ghqePœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "id": "xy-edge__ChatInput-fJHKg{œdataTypeœ:œChatInputœ,œidœ:œChatInput-fJHKgœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-03SGo{œfieldNameœ:œinput_valueœ,œidœ:œAgent-03SGoœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "ChatInput-fJHKg", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-fJHKgœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-03SGo", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-03SGoœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { - "className": "", "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-ghqeP", + "id": "Agent-03SGo", "name": "response", "output_types": [ "Message" @@ -92,7 +88,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-jwko6", + "id": "ChatOutput-ykhew", "inputTypes": [ "Data", "DataFrame", @@ -101,17 +97,17 @@ "type": "str" } }, - "id": "xy-edge__Agent-ghqeP{œdataTypeœ:œAgentœ,œidœ:œAgent-ghqePœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-jwko6{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-jwko6œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", - "source": "Agent-ghqeP", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-ghqePœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-jwko6", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-jwko6œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "id": "xy-edge__Agent-03SGo{œdataTypeœ:œAgentœ,œidœ:œAgent-03SGoœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-ykhew{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-ykhewœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "source": "Agent-03SGo", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-03SGoœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-ykhew", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-ykhewœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-IrBdK", + "id": "ChatInput-fJHKg", "node": { "base_classes": [ "Message" @@ -410,7 +406,7 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-IrBdK", + "id": "ChatInput-fJHKg", "measured": { "height": 48, "width": 192 @@ -424,7 +420,7 @@ }, { "data": { - "id": "ChatOutput-jwko6", + "id": "ChatOutput-ykhew", "node": { "base_classes": [ "Message" @@ -723,7 +719,7 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-jwko6", + "id": "ChatOutput-ykhew", "measured": { "height": 48, "width": 192 @@ -737,7 +733,7 @@ }, { "data": { - "id": "TavilySearchComponent-L8PP0", + "id": "TavilySearchComponent-nWDnP", "node": { "base_classes": [ "Data", @@ -796,7 +792,7 @@ "dynamic": false, "info": "Your Tavily API Key.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -804,7 +800,7 @@ "show": true, "title_case": false, "type": "str", - "value": "TAVILY_API_KEY" + "value": "" }, "chunks_per_source": { "_input_type": "IntInput", @@ -1118,7 +1114,7 @@ "type": "TavilySearchComponent" }, "dragging": false, - "id": "TavilySearchComponent-L8PP0", + "id": "TavilySearchComponent-nWDnP", "measured": { "height": 316, "width": 320 @@ -1134,7 +1130,7 @@ "data": { "description": "Uses AgentQL API to extract structured data from a given URL.", "display_name": "AgentQL Query Data", - "id": "AgentQL-fgRow", + "id": "AgentQL-qCiM5", "node": { "base_classes": [ "Data" @@ -1194,7 +1190,7 @@ "dynamic": false, "info": "Your AgentQL API key from dev.agentql.com", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -1202,7 +1198,7 @@ "show": true, "title_case": false, "type": "str", - "value": "AGENTQL_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1472,7 +1468,7 @@ "type": "AgentQL" }, "dragging": false, - "id": "AgentQL-fgRow", + "id": "AgentQL-qCiM5", "measured": { "height": 316, "width": 320 @@ -1486,7 +1482,7 @@ }, { "data": { - "id": "note-uI2ji", + "id": "note-Dw2MZ", "node": { "description": "### 💡 Add your OpenAI API key here", "display_name": "", @@ -1498,7 +1494,7 @@ "type": "note" }, "dragging": false, - "id": "note-uI2ji", + "id": "note-Dw2MZ", "measured": { "height": 324, "width": 324 @@ -1512,7 +1508,7 @@ }, { "data": { - "id": "note-K7Df4", + "id": "note-3fanj", "node": { "description": "### 💡 Add your AgentQL API key here", "display_name": "", @@ -1525,7 +1521,7 @@ }, "dragging": false, "height": 346, - "id": "note-K7Df4", + "id": "note-3fanj", "measured": { "height": 346, "width": 324 @@ -1539,7 +1535,7 @@ }, { "data": { - "id": "note-A4MCV", + "id": "note-L77iu", "node": { "description": "# Price Deal Finder \n\nThis flow searches and compares prices of a product on the web.\n## Prerequisites\n\n* **[AgentQL API Key](https://dev.agentql.com/api-keys)**\n* **[OpenAI API Key](https://platform.openai.com/)**\n* **[TavilyAI Search API Key](https://tavily.com/)**\n\n## Quick Start\n\n1. Add your [AgentQL API Key](https://dev.agentql.com/api-keys) to the **AgentQL** component.\n2. Add your [OpenAI API Key](https://platform.openai.com/) to the **Agent** component.\n3. Add your [TavilyAI Search API Key](https://tavily.com/) to the **Tavily AI Search** component.\n4. Click **Playground** and enter a product in chat. For example, search \"iPhone 16 Pro 512 GB\")\n* The **Agent** component populates the **Tavily AI Search** component's **Search Query** field, and the **Agent QL** component's **URL** and **Query** fields. \n\n* The **Agent** returns a structured response to your searcn in the chat.", "display_name": "", @@ -1550,7 +1546,7 @@ }, "dragging": false, "height": 674, - "id": "note-A4MCV", + "id": "note-L77iu", "measured": { "height": 674, "width": 466 @@ -1566,7 +1562,7 @@ }, { "data": { - "id": "note-AH0tj", + "id": "note-Op67v", "node": { "description": "### 💡 Add your Tavily AI Search key here", "display_name": "", @@ -1579,7 +1575,7 @@ }, "dragging": false, "height": 324, - "id": "note-AH0tj", + "id": "note-Op67v", "measured": { "height": 324, "width": 345 @@ -1595,7 +1591,7 @@ }, { "data": { - "id": "Agent-ghqeP", + "id": "Agent-03SGo", "node": { "base_classes": [ "Message" @@ -1621,22 +1617,13 @@ "max_retries", "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "mode", - "message", - "memory", - "sender_type", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, @@ -1665,7 +1652,7 @@ } ], "pinned": false, - "score": 5.283996070936036e-7, + "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -1763,7 +1750,7 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -1772,7 +1759,7 @@ "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1790,7 +1777,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1911,70 +1898,6 @@ "type": "int", "value": "" }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "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": true, - "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" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -2030,15 +1953,15 @@ "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, "list_add_label": "Add More", "name": "n_messages", "placeholder": "", "required": false, - "show": false, + "show": true, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -2064,30 +1987,6 @@ "type": "str", "value": "" }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, "seed": { "_input_type": "IntInput", "advanced": true, @@ -2106,100 +2005,6 @@ "type": "int", "value": 1 }, - "sender": { - "_input_type": "MessageTextInput", - "advanced": true, - "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.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": false, - "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, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, @@ -2223,7 +2028,7 @@ "trace_as_input": true, "trace_as_metadata": true, "type": "str", - "value": "You are a helpful assistant that can use tools to answer questions and perform tasks." + "value": "You are an deal finder assistant that helps find and compare the prices of products across different e-commerce platforms. You must use the Tavily Search API to find the URLs of the ecommerce platforms that sell these products. Then use the AgentQL tool to extract the prices of the product in those websites. Make sure to include the name of the product, the price of the product, the shop name, and the URL link of the page to where you can add the product to a cart or checkout immediately. The price and URL link has to be retrieved, so if it's not available or doesn't work don't include it.\n\nHere's how to write an AgentQL query:\n\nThe AgentQL query serves as the building block of your script. This guide shows you how AgentQL's query structure works and how to write a valid query.\n\n### Single term query\n\nA **single term query** enables you to retrieve a single element on the webpage. Here is an example of how you can write a single term query to retrieve a search box.\n\n```AgentQL\n{\n search_box\n}\n```\n\n### List term query\n\nA **list term query** enables you to retrieve a list of similar elements on the webpage. Here is an example of how you can write a list term query to retrieve a list of prices of apples.\n\n```AgentQL\n{\n apple_price[]\n}\n```\n\nYou can also specify the exact field you want to return in the list. Here is an example of how you can specify that you want the name and price from the list of products.\n\n```AgentQL\n{\n products[] {\n name\n price(integer)\n }\n}\n```\n\n### Combining single term queries and list term queries\n\nYou can query for both **single terms** and **list terms** by combining the preceding formats.\n\n```AgentQL\n{\n author\n date_of_birth\n book_titles[]\n}\n```\n\n### Giving context to queries\n\nThere two main ways you can provide additional context to your queries.\n\n#### Structural context\n\nYou can nest queries within parent containers to indicate that your target web element is in a particular section of the webpage.\n\n```AgentQL\n{\n footer {\n social_media_links[]\n }\n}\n```\n\n#### Semantic context\n\nYou can also provide a short description within parentheses to guide AgentQL in locating the right element(s).\n\n```AgentQL\n{\n footer {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n }\n}\n```\n\n### Syntax guidelines\n\nEnclose all AgentQL query terms within curly braces `{}`. The following query structure isn't valid because the term \"social_media_links\" is wrongly enclosed within parenthesis`()`.\n\n```AgentQL\n( # Should be {\n social_media_links(The icons that lead to Facebook, Snapchat, etc.)[]\n) # Should be }\n```\n\nYou can't include new lines in your semantic context. The following query structure isn't valid because the semantic context isn't contained within one line.\n\n```AgentQL\n{\n social_media_links(The icons that lead\n to Facebook, Snapchat, etc.)[]\n}\n```" }, "temperature": { "_input_type": "SliderInput", @@ -2253,31 +2058,6 @@ "type": "slider", "value": 0.1 }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" - }, "timeout": { "_input_type": "IntInput", "advanced": true, @@ -2341,28 +2121,28 @@ "type": "Agent" }, "dragging": false, - "id": "Agent-ghqeP", + "id": "Agent-03SGo", "measured": { - "height": 593, + "height": 594, "width": 320 }, "position": { - "x": 797.0440572927098, - "y": 100.6793034234862 + "x": 780.1868307050428, + "y": 115.01999131645616 }, "selected": false, "type": "genericNode" } ], "viewport": { - "x": 419.87135539102786, - "y": 101.46023627307682, - "zoom": 0.7403965178705934 + "x": 167.04286979104586, + "y": 184.39616411908878, + "zoom": 0.6920869578393206 } }, "description": "Searches and compares product prices across multiple e-commerce platforms. ", "endpoint_name": null, - "id": "a7e19be8-8f6d-4a1d-b74e-d00d50d6fa88", + "id": "e60f747f-c5c4-4581-b3cb-d320af9f7dce", "is_component": false, "last_tested_version": "1.4.3", "name": "Price Deal Finder", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json index cc78bc977..30e8b374a 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-BUgw3", + "id": "ChatInput-w2Y9B", "name": "message", "output_types": [ "Message" @@ -15,7 +15,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Prompt-gjXon", + "id": "Prompt-QckTl", "inputTypes": [ "Message", "Text" @@ -23,161 +23,19 @@ "type": "str" } }, - "id": "reactflow__edge-ChatInput-BUgw3{œdataTypeœ:œChatInputœ,œidœ:œChatInput-BUgw3œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-gjXon{œfieldNameœ:œinput_valueœ,œidœ:œPrompt-gjXonœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-w2Y9B{œdataTypeœ:œChatInputœ,œidœ:œChatInput-w2Y9Bœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Prompt-QckTl{œfieldNameœ:œinput_valueœ,œidœ:œPrompt-QckTlœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-BUgw3", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-BUgw3œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-gjXon", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œPrompt-gjXonœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "source": "ChatInput-w2Y9B", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-w2Y9Bœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-QckTl", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œPrompt-QckTlœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "animated": false, - "className": "", "data": { "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-pmjSJ", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-Z2V8G", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-pmjSJ{œdataTypeœ:œPromptœ,œidœ:œPrompt-pmjSJœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-Z2V8G{œfieldNameœ:œinput_valueœ,œidœ:œAgent-Z2V8Gœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-pmjSJ", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-pmjSJœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-Z2V8G", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-Z2V8Gœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Agent", - "id": "Agent-Z2V8G", - "name": "response", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "search_results", - "id": "Prompt-gjXon", - "inputTypes": [ - "Message", - "Text" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Agent-Z2V8G{œdataTypeœ:œAgentœ,œidœ:œAgent-Z2V8Gœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-gjXon{œfieldNameœ:œsearch_resultsœ,œidœ:œPrompt-gjXonœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Agent-Z2V8G", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-Z2V8Gœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-gjXon", - "targetHandle": "{œfieldNameœ: œsearch_resultsœ, œidœ: œPrompt-gjXonœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "TavilySearchComponent", - "id": "TavilySearchComponent-bQqQ3", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-Z2V8G", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "reactflow__edge-TavilySearchComponent-bQqQ3{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-bQqQ3œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-Z2V8G{œfieldNameœ:œtoolsœ,œidœ:œAgent-Z2V8Gœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "TavilySearchComponent-bQqQ3", - "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-bQqQ3œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-Z2V8G", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-Z2V8Gœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-GEpb2", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "system_message", - "id": "OpenAIModel-6XjJL", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-GEpb2{œdataTypeœ:œPromptœ,œidœ:œPrompt-GEpb2œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-6XjJL{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-6XjJLœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-GEpb2", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-GEpb2œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-6XjJL", - "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-6XjJLœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-BUgw3", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-6XjJL", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-ChatInput-BUgw3{œdataTypeœ:œChatInputœ,œidœ:œChatInput-BUgw3œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-6XjJL{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-6XjJLœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-BUgw3", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-BUgw3œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-6XjJL", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-6XjJLœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-6XjJL", + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-sOuA1", "name": "text_output", "output_types": [ "Message" @@ -185,7 +43,7 @@ }, "targetHandle": { "fieldName": "previous_response", - "id": "Prompt-pmjSJ", + "id": "Prompt-SUWLk", "inputTypes": [ "Message", "Text" @@ -193,48 +51,19 @@ "type": "str" } }, - "id": "reactflow__edge-OpenAIModel-6XjJL{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-6XjJLœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-pmjSJ{œfieldNameœ:œprevious_responseœ,œidœ:œPrompt-pmjSJœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "xy-edge__LanguageModelComponent-sOuA1{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-sOuA1œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-Prompt-SUWLk{œfieldNameœ:œprevious_responseœ,œidœ:œPrompt-SUWLkœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "OpenAIModel-6XjJL", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-6XjJLœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-pmjSJ", - "targetHandle": "{œfieldNameœ: œprevious_responseœ, œidœ: œPrompt-pmjSJœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "source": "LanguageModelComponent-sOuA1", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-sOuA1œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-SUWLk", + "targetHandle": "{œfieldNameœ: œprevious_responseœ, œidœ: œPrompt-SUWLkœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-gjXon", - "name": "prompt", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "OpenAIModel-rCRSl", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "reactflow__edge-Prompt-gjXon{œdataTypeœ:œPromptœ,œidœ:œPrompt-gjXonœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-rCRSl{œfieldNameœ:œinput_valueœ,œidœ:œOpenAIModel-rCRSlœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "Prompt-gjXon", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-gjXonœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-rCRSl", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œOpenAIModel-rCRSlœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "Prompt", - "id": "Prompt-LzmiE", + "id": "Prompt-SxdsY", "name": "prompt", "output_types": [ "Message" @@ -242,27 +71,107 @@ }, "targetHandle": { "fieldName": "system_message", - "id": "OpenAIModel-rCRSl", + "id": "LanguageModelComponent-sOuA1", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-LzmiE{œdataTypeœ:œPromptœ,œidœ:œPrompt-LzmiEœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-OpenAIModel-rCRSl{œfieldNameœ:œsystem_messageœ,œidœ:œOpenAIModel-rCRSlœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__Prompt-SxdsY{œdataTypeœ:œPromptœ,œidœ:œPrompt-SxdsYœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-sOuA1{œfieldNameœ:œsystem_messageœ,œidœ:œLanguageModelComponent-sOuA1œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-LzmiE", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-LzmiEœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "OpenAIModel-rCRSl", - "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œOpenAIModel-rCRSlœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-SxdsY", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-SxdsYœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-sOuA1", + "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œLanguageModelComponent-sOuA1œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, - "className": "", "data": { "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-rCRSl", + "dataType": "ChatInput", + "id": "ChatInput-w2Y9B", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "LanguageModelComponent-sOuA1", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__ChatInput-w2Y9B{œdataTypeœ:œChatInputœ,œidœ:œChatInput-w2Y9Bœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-sOuA1{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-sOuA1œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-w2Y9B", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-w2Y9Bœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-sOuA1", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-sOuA1œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-HX8fy", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "system_message", + "id": "LanguageModelComponent-PlT75", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Prompt-HX8fy{œdataTypeœ:œPromptœ,œidœ:œPrompt-HX8fyœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-PlT75{œfieldNameœ:œsystem_messageœ,œidœ:œLanguageModelComponent-PlT75œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Prompt-HX8fy", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-HX8fyœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-PlT75", + "targetHandle": "{œfieldNameœ: œsystem_messageœ, œidœ: œLanguageModelComponent-PlT75œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-QckTl", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "LanguageModelComponent-PlT75", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Prompt-QckTl{œdataTypeœ:œPromptœ,œidœ:œPrompt-QckTlœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-LanguageModelComponent-PlT75{œfieldNameœ:œinput_valueœ,œidœ:œLanguageModelComponent-PlT75œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Prompt-QckTl", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-QckTlœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "LanguageModelComponent-PlT75", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œLanguageModelComponent-PlT75œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-PlT75", "name": "text_output", "output_types": [ "Message" @@ -270,7 +179,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-qShGq", + "id": "ChatOutput-LWhiD", "inputTypes": [ "Data", "DataFrame", @@ -279,12 +188,92 @@ "type": "other" } }, - "id": "reactflow__edge-OpenAIModel-rCRSl{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-rCRSlœ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-qShGq{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-qShGqœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "xy-edge__LanguageModelComponent-PlT75{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-PlT75œ,œnameœ:œtext_outputœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-LWhiD{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-LWhiDœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "OpenAIModel-rCRSl", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-rCRSlœ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-qShGq", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-qShGqœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "LanguageModelComponent-PlT75", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-PlT75œ, œnameœ: œtext_outputœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-LWhiD", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-LWhiDœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "Prompt", + "id": "Prompt-SUWLk", + "name": "prompt", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-MoaC7", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__Prompt-SUWLk{œdataTypeœ:œPromptœ,œidœ:œPrompt-SUWLkœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-MoaC7{œfieldNameœ:œinput_valueœ,œidœ:œAgent-MoaC7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "Prompt-SUWLk", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-SUWLkœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-MoaC7", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-MoaC7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "TavilySearchComponent", + "id": "TavilySearchComponent-fpZy1", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-MoaC7", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__TavilySearchComponent-fpZy1{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-fpZy1œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-MoaC7{œfieldNameœ:œtoolsœ,œidœ:œAgent-MoaC7œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "selected": false, + "source": "TavilySearchComponent-fpZy1", + "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-fpZy1œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-MoaC7", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-MoaC7œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "Agent", + "id": "Agent-MoaC7", + "name": "response", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "search_results", + "id": "Prompt-QckTl", + "inputTypes": [ + "Message", + "Text" + ], + "type": "str" + } + }, + "id": "xy-edge__Agent-MoaC7{œdataTypeœ:œAgentœ,œidœ:œAgent-MoaC7œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-QckTl{œfieldNameœ:œsearch_resultsœ,œidœ:œPrompt-QckTlœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "source": "Agent-MoaC7", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-MoaC7œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-QckTl", + "targetHandle": "{œfieldNameœ: œsearch_resultsœ, œidœ: œPrompt-QckTlœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" } ], "nodes": [ @@ -292,7 +281,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-pmjSJ", + "id": "Prompt-SUWLk", "node": { "base_classes": [ "Message" @@ -425,7 +414,7 @@ }, "dragging": false, "height": 347, - "id": "Prompt-pmjSJ", + "id": "Prompt-SUWLk", "measured": { "height": 347, "width": 320 @@ -444,7 +433,7 @@ }, { "data": { - "id": "ChatInput-BUgw3", + "id": "ChatInput-w2Y9B", "node": { "base_classes": [ "Message" @@ -723,7 +712,7 @@ }, "dragging": false, "height": 234, - "id": "ChatInput-BUgw3", + "id": "ChatInput-w2Y9B", "measured": { "height": 234, "width": 320 @@ -744,7 +733,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-gjXon", + "id": "Prompt-QckTl", "node": { "base_classes": [ "Message" @@ -901,7 +890,7 @@ }, "dragging": false, "height": 433, - "id": "Prompt-gjXon", + "id": "Prompt-QckTl", "measured": { "height": 433, "width": 320 @@ -920,7 +909,7 @@ }, { "data": { - "id": "note-KPs4x", + "id": "note-LF4Ii", "node": { "description": "# Research Agent \n\nWelcome to the Research Agent! This flow helps you conduct in-depth research on various topics using AI-powered tools and analysis.\n\n## Instructions\n1. Enter Your Research Query\n - Type your research question or topic into the Chat Input node.\n - Be specific and clear about what you want to investigate.\n\n2. Generate Research Plan\n - The system will create a focused research plan based on your query.\n - This plan includes key search queries and priorities.\n\n3. Conduct Web Search\n - The Tavily AI Search tool will perform web searches using the generated queries.\n - It focuses on finding academic and reliable sources.\n\n4. Analyze and Synthesize\n - The AI agent will review the search results and create a comprehensive synthesis.\n - The report includes an executive summary, methodology, findings, and conclusions.\n\n5. Review the Output\n - Read the final report in the Chat Output node.\n - Use this information as a starting point for further research or decision-making.\n\nRemember: You can refine your initial query for more specific results! 🔍📊", "display_name": "", @@ -933,10 +922,10 @@ }, "dragging": false, "height": 694, - "id": "note-KPs4x", + "id": "note-LF4Ii", "measured": { "height": 694, - "width": 325 + "width": 324 }, "position": { "x": 699.0962027485247, @@ -955,700 +944,11 @@ "type": "noteNode", "width": 324 }, - { - "data": { - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "id": "Agent-Z2V8G", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "output_schema", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "output_parser", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "lf_version": "1.4.3", - "metadata": {}, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Anthropic", - "Google Generative AI", - "Groq", - "OpenAI", - "Custom" - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "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 langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "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 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a research analyst with access to Tavily Search." - }, - "temperature": { - "_input_type": "FloatInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "list": false, - "name": "temperature", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "float", - "value": 0.1 - }, - "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}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "type": "Agent" - }, - "dragging": false, - "height": 658, - "id": "Agent-Z2V8G", - "measured": { - "height": 658, - "width": 320 - }, - "position": { - "x": 2156.60686936856, - "y": 439.4579572266066 - }, - "positionAbsolute": { - "x": 2156.60686936856, - "y": 439.4579572266066 - }, - "selected": false, - "type": "genericNode", - "width": 320 - }, { "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-GEpb2", + "id": "Prompt-SxdsY", "node": { "base_classes": [ "Message" @@ -1756,7 +1056,7 @@ }, "dragging": false, "height": 260, - "id": "Prompt-GEpb2", + "id": "Prompt-SxdsY", "measured": { "height": 260, "width": 320 @@ -1777,7 +1077,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-LzmiE", + "id": "Prompt-HX8fy", "node": { "base_classes": [ "Message" @@ -1885,7 +1185,7 @@ }, "dragging": false, "height": 260, - "id": "Prompt-LzmiE", + "id": "Prompt-HX8fy", "measured": { "height": 260, "width": 320 @@ -1904,7 +1204,7 @@ }, { "data": { - "id": "note-J4Hc2", + "id": "note-uzf9V", "node": { "description": "# 🔑 Tavily AI Search Needs API Key\n\nYou can get 1000 searches/month free [here](https://tavily.com/) ", "display_name": "", @@ -1917,10 +1217,10 @@ }, "dragging": false, "height": 325, - "id": "note-J4Hc2", + "id": "note-uzf9V", "measured": { "height": 325, - "width": 326 + "width": 325 }, "position": { "x": 1797.5781951055678, @@ -1936,7 +1236,7 @@ }, { "data": { - "id": "TavilySearchComponent-bQqQ3", + "id": "TavilySearchComponent-fpZy1", "node": { "base_classes": [ "Data", @@ -1995,7 +1295,7 @@ "dynamic": false, "info": "Your Tavily API Key.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -2317,7 +1617,7 @@ "type": "TavilySearchComponent" }, "dragging": false, - "id": "TavilySearchComponent-bQqQ3", + "id": "TavilySearchComponent-fpZy1", "measured": { "height": 316, "width": 320 @@ -2331,789 +1631,7 @@ }, { "data": { - "id": "OpenAIModel-6XjJL", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "category": "models", - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "key": "OpenAIModel", - "legacy": false, - "lf_version": "1.4.3", - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 0.14285714285714285, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - } - }, - "tool_mode": false - }, - "selected_output": "text_output", - "showNode": true, - "type": "OpenAIModel" - }, - "dragging": false, - "id": "OpenAIModel-6XjJL", - "measured": { - "height": 539, - "width": 320 - }, - "position": { - "x": 1455.1912046212385, - "y": 487.41889689444065 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "OpenAIModel-rCRSl", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "category": "models", - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "key": "OpenAIModel", - "legacy": false, - "lf_version": "1.4.3", - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 0.14285714285714285, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - } - }, - "tool_mode": false - }, - "selected_output": "text_output", - "showNode": true, - "type": "OpenAIModel" - }, - "dragging": false, - "id": "OpenAIModel-rCRSl", - "measured": { - "height": 539, - "width": 320 - }, - "position": { - "x": 2869.8759720421745, - "y": 463.310915040386 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "ChatOutput-qShGq", + "id": "ChatOutput-LWhiD", "node": { "base_classes": [ "Message" @@ -3409,7 +1927,7 @@ "showNode": false, "type": "ChatOutput" }, - "id": "ChatOutput-qShGq", + "id": "ChatOutput-LWhiD", "measured": { "height": 48, "width": 192 @@ -3420,17 +1938,1145 @@ }, "selected": false, "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-sOuA1", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Runs a language model given a specified provider. ", + "display_name": "Language Model", + "documentation": "", + "edited": false, + "field_order": [ + "provider", + "model_name", + "api_key", + "input_value", + "system_message", + "stream", + "temperature" + ], + "frozen": false, + "icon": "brain-circuit", + "legacy": false, + "metadata": { + "keywords": [ + "model", + "llm", + "language model", + "large language model" + ] + }, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Model Response", + "group_outputs": false, + "method": "text_response", + "name": "text_output", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "allows_loop": false, + "cache": true, + "display_name": "Language Model", + "group_outputs": false, + "method": "build_model", + "name": "model_output", + "options": null, + "required_inputs": null, + "selected": "LanguageModel", + "tool_mode": true, + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "priority": 0, + "template": { + "_type": "Component", + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "Model Provider API key", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "System Message", + "dynamic": false, + "info": "A system message that helps set the behavior of the assistant", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "Controls randomness in responses", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + } + }, + "tool_mode": false + }, + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-sOuA1", + "measured": { + "height": 534, + "width": 320 + }, + "position": { + "x": 1456.7250059464952, + "y": 576.3277108797026 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-PlT75", + "node": { + "base_classes": [ + "LanguageModel", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Runs a language model given a specified provider. ", + "display_name": "Language Model", + "documentation": "", + "edited": false, + "field_order": [ + "provider", + "model_name", + "api_key", + "input_value", + "system_message", + "stream", + "temperature" + ], + "frozen": false, + "icon": "brain-circuit", + "legacy": false, + "metadata": { + "keywords": [ + "model", + "llm", + "language model", + "large language model" + ] + }, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Model Response", + "group_outputs": false, + "method": "text_response", + "name": "text_output", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + }, + { + "allows_loop": false, + "cache": true, + "display_name": "Language Model", + "group_outputs": false, + "method": "build_model", + "name": "model_output", + "options": null, + "required_inputs": null, + "selected": "LanguageModel", + "tool_mode": true, + "types": [ + "LanguageModel" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "priority": 0, + "template": { + "_type": "Component", + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "Model Provider API key", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "System Message", + "dynamic": false, + "info": "A system message that helps set the behavior of the assistant", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_message", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "Controls randomness in responses", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + } + }, + "tool_mode": false + }, + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-PlT75", + "measured": { + "height": 534, + "width": 320 + }, + "position": { + "x": 2910.7639501961753, + "y": 525.1670813598067 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "Agent-MoaC7", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "category": "agents", + "conditional_paths": [], + "custom_fields": {}, + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "Agent", + "documentation": "", + "edited": false, + "field_order": [ + "agent_llm", + "max_tokens", + "model_kwargs", + "json_mode", + "model_name", + "openai_api_base", + "api_key", + "temperature", + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" + ], + "frozen": false, + "icon": "bot", + "key": "Agent", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Response", + "group_outputs": false, + "method": "message_response", + "name": "response", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 1.1732828199964098e-19, + "template": { + "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "input_value": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input provided by the user for the agent to process.", + "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": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "json_mode": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "JSON Mode", + "dynamic": false, + "info": "If True, it will output JSON regardless of passing a schema.", + "list": false, + "list_add_label": "Add More", + "name": "json_mode", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, + "max_retries": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "The maximum number of retries to make when generating.", + "list": false, + "list_add_label": "Add More", + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_tokens": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "list_add_label": "Add More", + "name": "max_tokens", + "placeholder": "", + "range_spec": { + "max": 128000, + "min": 0, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "Additional keyword arguments to pass to the model.", + "list": false, + "list_add_label": "Add More", + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": true, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo", + "o1" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "openai_api_base": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "seed": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "list_add_label": "Add More", + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "system_prompt": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Agent Instructions", + "dynamic": false, + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_prompt", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "You are a helpful assistant that can use tools to answer questions and perform tasks." + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "The timeout for requests to OpenAI completion API.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "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": "Agent" + }, + "dragging": false, + "id": "Agent-MoaC7", + "measured": { + "height": 594, + "width": 320 + }, + "position": { + "x": 2160.8568280229615, + "y": 389.1875134253461 + }, + "selected": false, + "type": "genericNode" } ], "viewport": { - "x": -270.56486809177886, - "y": 55.40724387742989, - "zoom": 0.4817049597080576 + "x": -452.2155312664106, + "y": 38.345280955821636, + "zoom": 0.5605695956250395 } }, "description": "Agent that generates focused plans, conducts web searches, and synthesizes findings into comprehensive reports.", "endpoint_name": null, - "id": "c42f508b-de52-4d07-b2fa-ffe15e5212a1", + "id": "870092d6-5d88-42d5-b0c4-2e7385851b75", "is_component": false, "last_tested_version": "1.4.3", "name": "Research Agent", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json b/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json index 2401f5d46..708d719b7 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json @@ -3,11 +3,10 @@ "edges": [ { "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-PX9QB", + "id": "Prompt-fkLY7", "name": "prompt", "output_types": [ "Message" @@ -15,27 +14,26 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-sir3U", + "id": "Agent-bNGtH", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-PX9QB{œdataTypeœ:œPromptœ,œidœ:œPrompt-PX9QBœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-sir3U{œfieldNameœ:œinput_valueœ,œidœ:œAgent-sir3Uœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "xy-edge__Prompt-fkLY7{œdataTypeœ:œPromptœ,œidœ:œPrompt-fkLY7œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-bNGtH{œfieldNameœ:œinput_valueœ,œidœ:œAgent-bNGtHœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-PX9QB", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-PX9QBœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-sir3U", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-sir3Uœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-fkLY7", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-fkLY7œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-bNGtH", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-bNGtHœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "CalculatorComponent", - "id": "CalculatorComponent-JhT2c", + "id": "CalculatorComponent-nctUz", "name": "component_as_tool", "output_types": [ "Tool" @@ -43,27 +41,25 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-sir3U", + "id": "Agent-bNGtH", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-CalculatorComponent-JhT2c{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-JhT2cœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-sir3U{œfieldNameœ:œtoolsœ,œidœ:œAgent-sir3Uœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "xy-edge__CalculatorComponent-nctUz{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-nctUzœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-bNGtH{œfieldNameœ:œtoolsœ,œidœ:œAgent-bNGtHœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "CalculatorComponent-JhT2c", - "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-JhT2cœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-sir3U", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-sir3Uœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "CalculatorComponent-nctUz", + "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-nctUzœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-bNGtH", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-bNGtHœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { - "animated": false, - "className": "", "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-sir3U", + "id": "Agent-bNGtH", "name": "response", "output_types": [ "Message" @@ -71,7 +67,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-tv6P2", + "id": "ChatOutput-Bdpjz", "inputTypes": [ "Data", "DataFrame", @@ -80,12 +76,11 @@ "type": "other" } }, - "id": "xy-edge__Agent-sir3U{œdataTypeœ:œAgentœ,œidœ:œAgent-sir3Uœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-tv6P2{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-tv6P2œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", - "selected": false, - "source": "Agent-sir3U", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-sir3Uœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-tv6P2", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-tv6P2œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "id": "xy-edge__Agent-bNGtH{œdataTypeœ:œAgentœ,œidœ:œAgent-bNGtHœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Bdpjz{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Bdpjzœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "source": "Agent-bNGtH", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-bNGtHœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-Bdpjz", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Bdpjzœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" } ], "nodes": [ @@ -93,7 +88,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-PX9QB", + "id": "Prompt-fkLY7", "node": { "base_classes": [ "Message" @@ -322,7 +317,7 @@ }, "dragging": false, "height": 693, - "id": "Prompt-PX9QB", + "id": "Prompt-fkLY7", "measured": { "height": 693, "width": 320 @@ -343,7 +338,7 @@ "data": { "description": "Display a chat message in the Playground.", "display_name": "Chat Output", - "id": "ChatOutput-tv6P2", + "id": "ChatOutput-Bdpjz", "node": { "base_classes": [ "Message" @@ -638,7 +633,7 @@ }, "dragging": false, "height": 234, - "id": "ChatOutput-tv6P2", + "id": "ChatOutput-Bdpjz", "measured": { "height": 234, "width": 320 @@ -651,13 +646,13 @@ "x": 2240.3625274769397, "y": 355.16302699218204 }, - "selected": true, + "selected": false, "type": "genericNode", "width": 320 }, { "data": { - "id": "note-PwGXK", + "id": "note-EkBec", "node": { "description": "# SaaS Pricing Calculator\n\nWelcome to the SaaS Pricing Calculator! This flow helps you determine the optimal monthly subscription price for your software service.\n\n## Instructions\n\n1. Prepare Your Data\n - Gather information on monthly infrastructure costs\n - Calculate customer support expenses\n - Estimate continuous development costs\n - Decide on your desired profit margin\n - Determine the estimated number of subscribers\n\n2. Input Values\n - Enter the gathered data into the respective fields in the Prompt node\n - Double-check the accuracy of your inputs\n\n3. Run the Flow\n - Click the \"Run\" button to start the calculation process\n - The flow will use Chain-of-Thought prompting to guide the AI through the steps\n\n4. Review the Results\n - Examine the output in the Chat Output node\n - The result will show a breakdown of costs and the final subscription price\n\n5. Adjust and Refine\n - If needed, modify your inputs to explore different pricing scenarios\n - Re-run the flow to see how changes affect the final price\n\nRemember: Regularly update your costs and subscriber estimates to keep your pricing model accurate and competitive! 💼📊", "display_name": "", @@ -668,10 +663,10 @@ }, "dragging": false, "height": 800, - "id": "note-PwGXK", + "id": "note-EkBec", "measured": { "height": 800, - "width": 325 + "width": 324 }, "position": { "x": 689.7659055360411, @@ -692,696 +687,7 @@ }, { "data": { - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "id": "Agent-sir3U", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "output_schema", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "output_parser", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "lf_version": "1.4.2", - "metadata": {}, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Anthropic", - "Google Generative AI", - "Groq", - "OpenAI", - "Custom" - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "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 langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "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 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "# Subscription Pricing Calculator\n\n## Purpose\nCalculate the optimal monthly subscription price for a software product based on operational costs, desired profit margin, and estimated subscriber base.\n\n## Input Variables\nThe system requires the following inputs:\n- Monthly infrastructure costs (numeric)\n- Customer support costs (numeric)\n- Continuous development costs (numeric)\n- Desired profit margin (percentage)\n- Estimated number of subscribers (numeric)\n\n## Calculation Process\nFollow these steps to determine the subscription price:\n\n### Step 1: Total Monthly Costs\nCalculate the sum of all fixed operational costs:\n```\ntotal_monthly_costs = infrastructure_costs + support_costs + development_costs\n```\n\n### Step 2: Profit Margin Calculation\nCalculate the profit margin amount based on total costs:\n```\nprofit_amount = total_monthly_costs × (profit_margin_percentage / 100)\n```\n\n### Step 3: Total Revenue Required\nCalculate the total monthly revenue needed:\n```\ntotal_revenue_needed = total_monthly_costs + profit_amount\n```\n\n### Step 4: Per-Subscriber Price\nCalculate the minimum price per subscriber:\n```\nsubscription_price = total_revenue_needed ÷ estimated_subscribers\n```\n\n## Output Format\nPresent the results in the following structure:\n\nFixed costs: [sum of all costs]\nProfit margin: [calculated profit amount]\nTotal amount needed: [total revenue required]\nPrice per subscriber: [calculated subscription price]\n\nFinal recommendation: \"The minimum subscription price per subscriber should be [price] to achieve the desired profit margin of [percentage]%\"\n\n## Notes\n- All monetary values should be rounded to 2 decimal places\n- Ensure all input values are positive numbers\n- Validate that the estimated subscribers count is greater than zero\n- The profit margin percentage should be between 0 and 100" - }, - "temperature": { - "_input_type": "FloatInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "list": false, - "name": "temperature", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "float", - "value": 0.1 - }, - "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}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "type": "Agent" - }, - "dragging": false, - "height": 650, - "id": "Agent-sir3U", - "measured": { - "height": 650, - "width": 320 - }, - "position": { - "x": 1819.2633856623966, - "y": 138.32023808479687 - }, - "positionAbsolute": { - "x": 1819.2633856623966, - "y": 138.32023808479687 - }, - "selected": false, - "type": "genericNode", - "width": 320 - }, - { - "data": { - "id": "CalculatorComponent-JhT2c", + "id": "CalculatorComponent-nctUz", "node": { "base_classes": [ "Data" @@ -1516,7 +822,7 @@ "type": "CalculatorComponent" }, "dragging": false, - "id": "CalculatorComponent-JhT2c", + "id": "CalculatorComponent-nctUz", "measured": { "height": 218, "width": 320 @@ -1527,19 +833,563 @@ }, "selected": false, "type": "genericNode" + }, + { + "data": { + "id": "Agent-bNGtH", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "category": "agents", + "conditional_paths": [], + "custom_fields": {}, + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "Agent", + "documentation": "", + "edited": false, + "field_order": [ + "agent_llm", + "max_tokens", + "model_kwargs", + "json_mode", + "model_name", + "openai_api_base", + "api_key", + "temperature", + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" + ], + "frozen": false, + "icon": "bot", + "key": "Agent", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Response", + "group_outputs": false, + "method": "message_response", + "name": "response", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "score": 5.283996070936036e-7, + "template": { + "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "input_value": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input provided by the user for the agent to process.", + "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": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "json_mode": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "JSON Mode", + "dynamic": false, + "info": "If True, it will output JSON regardless of passing a schema.", + "list": false, + "list_add_label": "Add More", + "name": "json_mode", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, + "max_retries": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "The maximum number of retries to make when generating.", + "list": false, + "list_add_label": "Add More", + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_tokens": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "list_add_label": "Add More", + "name": "max_tokens", + "placeholder": "", + "range_spec": { + "max": 128000, + "min": 0, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "Additional keyword arguments to pass to the model.", + "list": false, + "list_add_label": "Add More", + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": true, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo", + "o1" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "openai_api_base": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "seed": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "list_add_label": "Add More", + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "system_prompt": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Agent Instructions", + "dynamic": false, + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_prompt", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "# Subscription Pricing Calculator\n\n## Purpose\nCalculate the optimal monthly subscription price for a software product based on operational costs, desired profit margin, and estimated subscriber base.\n\n## Input Variables\nThe system requires the following inputs:\n- Monthly infrastructure costs (numeric)\n- Customer support costs (numeric)\n- Continuous development costs (numeric)\n- Desired profit margin (percentage)\n- Estimated number of subscribers (numeric)\n\n## Calculation Process\nFollow these steps to determine the subscription price:\n\n### Step 1: Total Monthly Costs\nCalculate the sum of all fixed operational costs:\n```\ntotal_monthly_costs = infrastructure_costs + support_costs + development_costs\n```\n\n### Step 2: Profit Margin Calculation\nCalculate the profit margin amount based on total costs:\n```\nprofit_amount = total_monthly_costs × (profit_margin_percentage / 100)\n```\n\n### Step 3: Total Revenue Required\nCalculate the total monthly revenue needed:\n```\ntotal_revenue_needed = total_monthly_costs + profit_amount\n```\n\n### Step 4: Per-Subscriber Price\nCalculate the minimum price per subscriber:\n```\nsubscription_price = total_revenue_needed ÷ estimated_subscribers\n```\n\n## Output Format\nPresent the results in the following structure:\n\nFixed costs: [sum of all costs]\nProfit margin: [calculated profit amount]\nTotal amount needed: [total revenue required]\nPrice per subscriber: [calculated subscription price]\n\nFinal recommendation: \"The minimum subscription price per subscriber should be [price] to achieve the desired profit margin of [percentage]%\"\n\n## Notes\n- All monetary values should be rounded to 2 decimal places\n- Ensure all input values are positive numbers\n- Validate that the estimated subscribers count is greater than zero\n- The profit margin percentage should be between 0 and 100" + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "The timeout for requests to OpenAI completion API.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "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": "Agent" + }, + "dragging": false, + "id": "Agent-bNGtH", + "measured": { + "height": 594, + "width": 320 + }, + "position": { + "x": 1806.2557423829758, + "y": 208.92841227399322 + }, + "selected": false, + "type": "genericNode" } ], "viewport": { - "x": -514.4665122679305, - "y": 57.59497096606026, - "zoom": 0.5864177566573868 + "x": -268.94191765890173, + "y": -3.5404544751907565, + "zoom": 0.5406818687693208 } }, "description": "Calculate SaaS subscription price based on costs, profit margin, and subscribers using step-by-step method and Chain-of-Thought prompting. ", "endpoint_name": null, - "id": "45470d4c-fade-4ec5-8bc1-96f14160d957", + "id": "2fdf0fb0-bc36-428a-8f68-6c694b2d05c6", "is_component": false, - "last_tested_version": "1.4.2", + "last_tested_version": "1.4.3", "name": "SaaS Pricing", "tags": [ "agents", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json index 15ff34362..84119498d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json @@ -1,61 +1,11 @@ { "data": { "edges": [ - { - "data": { - "sourceHandle": { - "dataType": "ScrapeGraphSearchApi", - "id": "ScrapeGraphSearchApi-vo1Yo", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-xgcha", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "xy-edge__ScrapeGraphSearchApi-vo1Yo{œdataTypeœ:œScrapeGraphSearchApiœ,œidœ:œScrapeGraphSearchApi-vo1Yoœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-xgcha{œfieldNameœ:œtoolsœ,œidœ:œAgent-xgchaœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "source": "ScrapeGraphSearchApi-vo1Yo", - "sourceHandle": "{œdataTypeœ: œScrapeGraphSearchApiœ, œidœ: œScrapeGraphSearchApi-vo1Yoœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-xgcha", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-xgchaœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-v88Su", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-xgcha", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "xy-edge__ChatInput-v88Su{œdataTypeœ:œChatInputœ,œidœ:œChatInput-v88Suœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-xgcha{œfieldNameœ:œinput_valueœ,œidœ:œAgent-xgchaœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "source": "ChatInput-v88Su", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-v88Suœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-xgcha", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-xgchaœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, { "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-xgcha", + "id": "Agent-9JGgQ", "name": "response", "output_types": [ "Message" @@ -63,7 +13,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-7b1Kf", + "id": "ChatOutput-Pygov", "inputTypes": [ "Data", "DataFrame", @@ -72,17 +22,67 @@ "type": "other" } }, - "id": "xy-edge__Agent-xgcha{œdataTypeœ:œAgentœ,œidœ:œAgent-xgchaœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-7b1Kf{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-7b1Kfœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", - "source": "Agent-xgcha", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-xgchaœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-7b1Kf", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-7b1Kfœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "id": "xy-edge__Agent-9JGgQ{œdataTypeœ:œAgentœ,œidœ:œAgent-9JGgQœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Pygov{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Pygovœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "source": "Agent-9JGgQ", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-9JGgQœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-Pygov", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Pygovœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "ScrapeGraphSearchApi", + "id": "ScrapeGraphSearchApi-ww6QN", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-9JGgQ", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__ScrapeGraphSearchApi-ww6QN{œdataTypeœ:œScrapeGraphSearchApiœ,œidœ:œScrapeGraphSearchApi-ww6QNœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-9JGgQ{œfieldNameœ:œtoolsœ,œidœ:œAgent-9JGgQœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "source": "ScrapeGraphSearchApi-ww6QN", + "sourceHandle": "{œdataTypeœ: œScrapeGraphSearchApiœ, œidœ: œScrapeGraphSearchApi-ww6QNœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-9JGgQ", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-9JGgQœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-TzjdQ", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-9JGgQ", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "xy-edge__ChatInput-TzjdQ{œdataTypeœ:œChatInputœ,œidœ:œChatInput-TzjdQœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-9JGgQ{œfieldNameœ:œinput_valueœ,œidœ:œAgent-9JGgQœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "source": "ChatInput-TzjdQ", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-TzjdQœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-9JGgQ", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-9JGgQœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" } ], "nodes": [ { "data": { - "id": "ScrapeGraphSearchApi-vo1Yo", + "id": "ScrapeGraphSearchApi-ww6QN", "node": { "base_classes": [ "Data" @@ -110,9 +110,11 @@ "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": null, "method": "to_toolkit", "name": "component_as_tool", + "options": null, "required_inputs": null, "selected": "Tool", "tool_mode": true, @@ -132,7 +134,7 @@ "dynamic": false, "info": "The API key to use ScrapeGraph API.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -140,7 +142,7 @@ "show": true, "title_case": false, "type": "str", - "value": "SCRAPEGRAPH_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -161,11 +163,11 @@ "value": "from langflow.custom.custom_component.component import Component\nfrom langflow.io import (\n MessageTextInput,\n Output,\n SecretStrInput,\n)\nfrom langflow.schema.data import Data\n\n\nclass ScrapeGraphSearchApi(Component):\n display_name: str = \"ScrapeGraphSearchApi\"\n description: str = \"\"\"ScrapeGraph Search API.\n Given a search prompt, it will return search results using ScrapeGraph's search functionality.\n More info at https://docs.scrapegraphai.com/services/searchscraper\"\"\"\n name = \"ScrapeGraphSearchApi\"\n\n documentation: str = \"https://docs.scrapegraphai.com/introduction\"\n icon = \"ScrapeGraph\"\n\n inputs = [\n SecretStrInput(\n name=\"api_key\",\n display_name=\"ScrapeGraph API Key\",\n required=True,\n password=True,\n info=\"The API key to use ScrapeGraph API.\",\n ),\n MessageTextInput(\n name=\"user_prompt\",\n display_name=\"Search Prompt\",\n tool_mode=True,\n info=\"The search prompt to use.\",\n ),\n ]\n\n outputs = [\n Output(display_name=\"Data\", name=\"data\", method=\"search\"),\n ]\n\n def search(self) -> list[Data]:\n try:\n from scrapegraph_py import Client\n from scrapegraph_py.logger import sgai_logger\n except ImportError as e:\n msg = \"Could not import scrapegraph-py package. Please install it with `pip install scrapegraph-py`.\"\n raise ImportError(msg) from e\n\n # Set logging level\n sgai_logger.set_logging(level=\"INFO\")\n\n # Initialize the client with API key\n sgai_client = Client(api_key=self.api_key)\n\n try:\n # SearchScraper request\n response = sgai_client.searchscraper(\n user_prompt=self.user_prompt,\n )\n\n # Close the client\n sgai_client.close()\n\n return Data(data=response)\n except Exception:\n sgai_client.close()\n raise\n" }, "tools_metadata": { - "_input_type": "TableInput", + "_input_type": "ToolsInput", "advanced": false, - "display_name": "Edit tools", + "display_name": "Actions", "dynamic": false, - "info": "", + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", "is_list": true, "list_add_label": "Add More", "name": "tools_metadata", @@ -173,93 +175,28 @@ "real_time_refresh": true, "required": false, "show": true, - "table_icon": "Hammer", - "table_options": { - "block_add": true, - "block_delete": true, - "block_edit": true, - "block_filter": true, - "block_hide": true, - "block_select": true, - "block_sort": true, - "description": "Modify tool names and descriptions to help agents understand when to use each tool.", - "field_parsers": { - "commands": "commands", - "name": [ - "snake_case", - "no_blank" - ] - }, - "hide_options": true - }, - "table_schema": { - "columns": [ - { - "default": "None", - "description": "Specify the name of the tool.", - "disable_edit": false, - "display_name": "Tool Name", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "name", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "Describe the purpose of the tool.", - "disable_edit": false, - "display_name": "Tool Description", - "edit_mode": "popover", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "description", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "The default identifiers for the tools and cannot be changed.", - "disable_edit": true, - "display_name": "Tool Identifiers", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": true, - "name": "tags", - "sortable": false, - "type": "str" - }, - { - "default": true, - "description": "Indicates whether the tool is currently active. Set to True to activate this tool.", - "disable_edit": false, - "display_name": "Enable", - "edit_mode": "popover", - "filterable": true, - "formatter": "boolean", - "hidden": false, - "name": "status", - "sortable": true, - "type": "boolean" - } - ] - }, "title_case": false, "tool_mode": false, "trace_as_metadata": true, - "trigger_icon": "Hammer", - "trigger_text": "", - "type": "table", + "type": "tools", "value": [ { - "description": "search(api_key: Message) - ScrapeGraph Search API.\n Given a search prompt, it will return search results using ScrapeGraph's search functionality.\n More info at https://docs.scrapegraphai.com/services/searchscraper", - "name": "ScrapeGraphSearchApi-search", + "args": { + "user_prompt": { + "default": "", + "description": "The search prompt to use.", + "title": "User Prompt", + "type": "string" + } + }, + "description": "ScrapeGraph Search API.\n Given a search prompt, it will return search results using ScrapeGraph's search functionality.\n More info at https://docs.scrapegraphai.com/services/searchscraper", + "display_description": "ScrapeGraph Search API.\n Given a search prompt, it will return search results using ScrapeGraph's search functionality.\n More info at https://docs.scrapegraphai.com/services/searchscraper", + "display_name": "search", + "name": "search", + "readonly": false, + "status": true, "tags": [ - "ScrapeGraphSearchApi-search" + "search" ] } ] @@ -295,9 +232,9 @@ "type": "ScrapeGraphSearchApi" }, "dragging": false, - "id": "ScrapeGraphSearchApi-vo1Yo", + "id": "ScrapeGraphSearchApi-ww6QN", "measured": { - "height": 497, + "height": 348, "width": 320 }, "position": { @@ -309,7 +246,7 @@ }, { "data": { - "id": "ChatInput-v88Su", + "id": "ChatInput-TzjdQ", "node": { "base_classes": [ "Message" @@ -605,9 +542,9 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-v88Su", + "id": "ChatInput-TzjdQ", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -619,7 +556,7 @@ }, { "data": { - "id": "ChatOutput-7b1Kf", + "id": "ChatOutput-Pygov", "node": { "base_classes": [ "Message" @@ -913,9 +850,9 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-7b1Kf", + "id": "ChatOutput-Pygov", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -927,7 +864,7 @@ }, { "data": { - "id": "note-zsGwj", + "id": "note-Fffq1", "node": { "description": "## 🚀 ScrapeGraphAI Template 🔍\n\nThis template connects the **Search Point** endpoint from [ScrapeGraphAI](https://scrapegraphai.com) to an **Agent** component.\n\n## Prerequisites\n\n* [OpenAI API key](https://platform.openai.com/docs/overview)\n* [ScrapeGraphAI API key](https://dashboard.scrapegraphai.com)\n\n## Quickstart\n\n1. Add your **ScrapeGraphAI API key** to the **ScrapeGraphSearchApi** component.\n\n2. Add your **OpenAI API key** to the **Agent** component.\n\n3. Open the **Playground** and ask your Agent a question. The Agent uses ScrapeGraph as a tool to answer you.", "display_name": "", @@ -938,10 +875,10 @@ }, "dragging": false, "height": 584, - "id": "note-zsGwj", + "id": "note-Fffq1", "measured": { "height": 584, - "width": 346 + "width": 345 }, "position": { "x": -322.8560821408546, @@ -954,7 +891,7 @@ }, { "data": { - "id": "note-5PCHp", + "id": "note-IK0Uo", "node": { "description": "### 💡 Add your OpenAI API key here 👇", "display_name": "", @@ -966,7 +903,7 @@ "type": "note" }, "dragging": false, - "id": "note-5PCHp", + "id": "note-IK0Uo", "measured": { "height": 324, "width": 324 @@ -980,7 +917,7 @@ }, { "data": { - "id": "note-awQna", + "id": "note-zpH8d", "node": { "description": "### 💡 Add your ScrapeGraphAI API key here 👇", "display_name": "", @@ -993,10 +930,10 @@ }, "dragging": false, "height": 324, - "id": "note-awQna", + "id": "note-zpH8d", "measured": { "height": 324, - "width": 389 + "width": 390 }, "position": { "x": 8.432436918410303, @@ -1009,7 +946,7 @@ }, { "data": { - "id": "Agent-xgcha", + "id": "Agent-9JGgQ", "node": { "base_classes": [ "Message" @@ -1035,19 +972,13 @@ "max_retries", "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, @@ -1062,8 +993,11 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1073,7 +1007,7 @@ } ], "pinned": false, - "score": 5.283996070936036e-7, + "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -1137,30 +1071,18 @@ "Custom" ], "options_metadata": [ - { - "icon": "Amazon" - }, { "icon": "Anthropic" }, - { - "icon": "Azure" - }, { "icon": "GoogleGenerativeAI" }, { "icon": "Groq" }, - { - "icon": "NVIDIA" - }, { "icon": "OpenAI" }, - { - "icon": "SambaNova" - }, { "icon": "brain" } @@ -1170,6 +1092,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1182,15 +1105,16 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1208,7 +1132,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1329,70 +1253,6 @@ "type": "int", "value": "" }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -1439,17 +1299,18 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4.1" + "value": "gpt-4o" }, "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, "list_add_label": "Add More", "name": "n_messages", @@ -1481,29 +1342,6 @@ "type": "str", "value": "" }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, "seed": { "_input_type": "IntInput", "advanced": true, @@ -1522,101 +1360,6 @@ "type": "int", "value": 1 }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "options_metadata": [], - "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, - "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": "" - }, - "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, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, @@ -1670,31 +1413,6 @@ "type": "slider", "value": 0.1 }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "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}" - }, "timeout": { "_input_type": "IntInput", "advanced": true, @@ -1754,35 +1472,34 @@ }, "tool_mode": false }, - "selected_output": "response", "showNode": true, "type": "Agent" }, "dragging": false, - "id": "Agent-xgcha", + "id": "Agent-9JGgQ", "measured": { - "height": 624, + "height": 594, "width": 320 }, "position": { - "x": 431.89147640204374, - "y": 167.0120581775507 + "x": 408.0681140680749, + "y": 174.43740483203445 }, - "selected": false, + "selected": true, "type": "genericNode" } ], "viewport": { - "x": 386.73940143606825, - "y": -38.82793121290217, - "zoom": 0.9940070432926703 + "x": 272.56443721197843, + "y": 31.260463976456208, + "zoom": 0.9959993167224503 } }, "description": "Search the web for information.", "endpoint_name": null, - "id": "4f6f37d8-7738-45b0-a2e1-e33edcb30fe9", + "id": "33595f43-7565-44ff-a55e-02655b0a7cb9", "is_component": false, - "last_tested_version": "1.2.0", + "last_tested_version": "1.4.3", "name": "Search agent", "tags": [ "web-scraping", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json index 03fb79707..3e11e6dfd 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-WNOHC", + "id": "Prompt-m2JmU", "name": "prompt", "output_types": [ "Message" @@ -15,19 +15,19 @@ }, "targetHandle": { "fieldName": "system_prompt", - "id": "Agent-INg7A", + "id": "Agent-RBaM2", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-WNOHC{œdataTypeœ:œPromptœ,œidœ:œPrompt-WNOHCœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-INg7A{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-INg7Aœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Prompt-m2JmU{œdataTypeœ:œPromptœ,œidœ:œPrompt-m2JmUœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-RBaM2{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-RBaM2œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-WNOHC", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-WNOHCœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-INg7A", - "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-INg7Aœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-m2JmU", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-m2JmUœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-RBaM2", + "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-RBaM2œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -35,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-d1yBl", + "id": "Prompt-iDIlP", "name": "prompt", "output_types": [ "Message" @@ -43,19 +43,19 @@ }, "targetHandle": { "fieldName": "system_prompt", - "id": "Agent-xzdFp", + "id": "Agent-qBOQH", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-d1yBl{œdataTypeœ:œPromptœ,œidœ:œPrompt-d1yBlœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-xzdFp{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-xzdFpœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Prompt-iDIlP{œdataTypeœ:œPromptœ,œidœ:œPrompt-iDIlPœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-qBOQH{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-qBOQHœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-d1yBl", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-d1yBlœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-xzdFp", - "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-xzdFpœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-iDIlP", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-iDIlPœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-qBOQH", + "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-qBOQHœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -63,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-xzdFp", + "id": "Agent-qBOQH", "name": "response", "output_types": [ "Message" @@ -71,7 +71,7 @@ }, "targetHandle": { "fieldName": "finance_agent_output", - "id": "Prompt-WNOHC", + "id": "Prompt-m2JmU", "inputTypes": [ "Message", "Text" @@ -79,12 +79,12 @@ "type": "str" } }, - "id": "reactflow__edge-Agent-xzdFp{œdataTypeœ:œAgentœ,œidœ:œAgent-xzdFpœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-WNOHC{œfieldNameœ:œfinance_agent_outputœ,œidœ:œPrompt-WNOHCœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-qBOQH{œdataTypeœ:œAgentœ,œidœ:œAgent-qBOQHœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-m2JmU{œfieldNameœ:œfinance_agent_outputœ,œidœ:œPrompt-m2JmUœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-xzdFp", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-xzdFpœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-WNOHC", - "targetHandle": "{œfieldNameœ: œfinance_agent_outputœ, œidœ: œPrompt-WNOHCœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "source": "Agent-qBOQH", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-qBOQHœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-m2JmU", + "targetHandle": "{œfieldNameœ: œfinance_agent_outputœ, œidœ: œPrompt-m2JmUœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -92,7 +92,7 @@ "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-EXrQ4", + "id": "ChatInput-pauUk", "name": "message", "output_types": [ "Message" @@ -100,19 +100,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-mYTzY", + "id": "Agent-fFCyc", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-EXrQ4{œdataTypeœ:œChatInputœ,œidœ:œChatInput-EXrQ4œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-mYTzY{œfieldNameœ:œinput_valueœ,œidœ:œAgent-mYTzYœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-pauUk{œdataTypeœ:œChatInputœ,œidœ:œChatInput-pauUkœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-fFCyc{œfieldNameœ:œinput_valueœ,œidœ:œAgent-fFCycœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-EXrQ4", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-EXrQ4œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-mYTzY", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-mYTzYœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-pauUk", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-pauUkœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-fFCyc", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-fFCycœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -120,7 +120,7 @@ "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-f7d7X", + "id": "Prompt-7Qbz7", "name": "prompt", "output_types": [ "Message" @@ -128,19 +128,19 @@ }, "targetHandle": { "fieldName": "system_prompt", - "id": "Agent-mYTzY", + "id": "Agent-fFCyc", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-f7d7X{œdataTypeœ:œPromptœ,œidœ:œPrompt-f7d7Xœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-mYTzY{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-mYTzYœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Prompt-7Qbz7{œdataTypeœ:œPromptœ,œidœ:œPrompt-7Qbz7œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-fFCyc{œfieldNameœ:œsystem_promptœ,œidœ:œAgent-fFCycœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-f7d7X", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-f7d7Xœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-mYTzY", - "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-mYTzYœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-7Qbz7", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-7Qbz7œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-fFCyc", + "targetHandle": "{œfieldNameœ: œsystem_promptœ, œidœ: œAgent-fFCycœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -148,7 +148,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-mYTzY", + "id": "Agent-fFCyc", "name": "response", "output_types": [ "Message" @@ -156,19 +156,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-xzdFp", + "id": "Agent-qBOQH", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Agent-mYTzY{œdataTypeœ:œAgentœ,œidœ:œAgent-mYTzYœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-xzdFp{œfieldNameœ:œinput_valueœ,œidœ:œAgent-xzdFpœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-fFCyc{œdataTypeœ:œAgentœ,œidœ:œAgent-fFCycœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-qBOQH{œfieldNameœ:œinput_valueœ,œidœ:œAgent-qBOQHœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-mYTzY", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-mYTzYœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-xzdFp", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-xzdFpœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-fFCyc", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-fFCycœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-qBOQH", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-qBOQHœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -176,7 +176,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-mYTzY", + "id": "Agent-fFCyc", "name": "response", "output_types": [ "Message" @@ -184,7 +184,7 @@ }, "targetHandle": { "fieldName": "research_agent_output", - "id": "Prompt-WNOHC", + "id": "Prompt-m2JmU", "inputTypes": [ "Message", "Text" @@ -192,12 +192,12 @@ "type": "str" } }, - "id": "reactflow__edge-Agent-mYTzY{œdataTypeœ:œAgentœ,œidœ:œAgent-mYTzYœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-WNOHC{œfieldNameœ:œresearch_agent_outputœ,œidœ:œPrompt-WNOHCœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-fFCyc{œdataTypeœ:œAgentœ,œidœ:œAgent-fFCycœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Prompt-m2JmU{œfieldNameœ:œresearch_agent_outputœ,œidœ:œPrompt-m2JmUœ,œinputTypesœ:[œMessageœ,œTextœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-mYTzY", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-mYTzYœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-WNOHC", - "targetHandle": "{œfieldNameœ: œresearch_agent_outputœ, œidœ: œPrompt-WNOHCœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" + "source": "Agent-fFCyc", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-fFCycœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-m2JmU", + "targetHandle": "{œfieldNameœ: œresearch_agent_outputœ, œidœ: œPrompt-m2JmUœ, œinputTypesœ: [œMessageœ, œTextœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -205,7 +205,7 @@ "data": { "sourceHandle": { "dataType": "CalculatorComponent", - "id": "CalculatorComponent-9O7Ap", + "id": "CalculatorComponent-4CJEe", "name": "component_as_tool", "output_types": [ "Tool" @@ -213,19 +213,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-INg7A", + "id": "Agent-RBaM2", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-CalculatorComponent-9O7Ap{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-9O7Apœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-INg7A{œfieldNameœ:œtoolsœ,œidœ:œAgent-INg7Aœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-CalculatorComponent-4CJEe{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-4CJEeœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-RBaM2{œfieldNameœ:œtoolsœ,œidœ:œAgent-RBaM2œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "CalculatorComponent-9O7Ap", - "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-9O7Apœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-INg7A", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-INg7Aœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "CalculatorComponent-4CJEe", + "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-4CJEeœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-RBaM2", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-RBaM2œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -233,7 +233,7 @@ "data": { "sourceHandle": { "dataType": "YfinanceComponent", - "id": "YfinanceComponent-Adjq6", + "id": "YfinanceComponent-8yre9", "name": "component_as_tool", "output_types": [ "Tool" @@ -241,19 +241,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-xzdFp", + "id": "Agent-qBOQH", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-YfinanceComponent-Adjq6{œdataTypeœ:œYfinanceComponentœ,œidœ:œYfinanceComponent-Adjq6œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-xzdFp{œfieldNameœ:œtoolsœ,œidœ:œAgent-xzdFpœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-YfinanceComponent-8yre9{œdataTypeœ:œYfinanceComponentœ,œidœ:œYfinanceComponent-8yre9œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-qBOQH{œfieldNameœ:œtoolsœ,œidœ:œAgent-qBOQHœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "YfinanceComponent-Adjq6", - "sourceHandle": "{œdataTypeœ: œYfinanceComponentœ, œidœ: œYfinanceComponent-Adjq6œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-xzdFp", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-xzdFpœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "YfinanceComponent-8yre9", + "sourceHandle": "{œdataTypeœ: œYfinanceComponentœ, œidœ: œYfinanceComponent-8yre9œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-qBOQH", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-qBOQHœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -261,7 +261,7 @@ "data": { "sourceHandle": { "dataType": "TavilySearchComponent", - "id": "TavilySearchComponent-6ezaX", + "id": "TavilySearchComponent-tO0qf", "name": "component_as_tool", "output_types": [ "Tool" @@ -269,19 +269,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-mYTzY", + "id": "Agent-fFCyc", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-TavilySearchComponent-6ezaX{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-6ezaXœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-mYTzY{œfieldNameœ:œtoolsœ,œidœ:œAgent-mYTzYœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-TavilySearchComponent-tO0qf{œdataTypeœ:œTavilySearchComponentœ,œidœ:œTavilySearchComponent-tO0qfœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-fFCyc{œfieldNameœ:œtoolsœ,œidœ:œAgent-fFCycœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "TavilySearchComponent-6ezaX", - "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-6ezaXœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-mYTzY", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-mYTzYœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "TavilySearchComponent-tO0qf", + "sourceHandle": "{œdataTypeœ: œTavilySearchComponentœ, œidœ: œTavilySearchComponent-tO0qfœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-fFCyc", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-fFCycœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -289,7 +289,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-INg7A", + "id": "Agent-RBaM2", "name": "response", "output_types": [ "Message" @@ -297,7 +297,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-rF4Qx", + "id": "ChatOutput-l6yiS", "inputTypes": [ "Data", "DataFrame", @@ -306,12 +306,12 @@ "type": "other" } }, - "id": "reactflow__edge-Agent-INg7A{œdataTypeœ:œAgentœ,œidœ:œAgent-INg7Aœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-rF4Qx{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-rF4Qxœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-Agent-RBaM2{œdataTypeœ:œAgentœ,œidœ:œAgent-RBaM2œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-l6yiS{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-l6yiSœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "Agent-INg7A", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-INg7Aœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-rF4Qx", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-rF4Qxœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "Agent-RBaM2", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-RBaM2œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-l6yiS", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-l6yiSœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" } ], "nodes": [ @@ -319,7 +319,7 @@ "data": { "description": "Define the agent's instructions, then enter a task to complete using tools.", "display_name": "Finance Agent", - "id": "Agent-xzdFp", + "id": "Agent-qBOQH", "node": { "base_classes": [ "Message" @@ -336,34 +336,28 @@ "max_tokens", "model_kwargs", "json_mode", - "output_schema", "model_name", "openai_api_base", "api_key", "temperature", "seed", - "output_parser", + "max_retries", + "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, "icon": "bot", "legacy": false, - "lf_version": "1.0.19.post2", "metadata": {}, + "minimized": false, "output_types": [], "outputs": [ { @@ -371,8 +365,11 @@ "cache": true, "display_name": "Response", "group_outputs": false, + "hidden": null, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -391,11 +388,13 @@ "dynamic": false, "info": "If true, will add a tool to the agent that returns the current date.", "list": false, + "list_add_label": "Add More", "name": "add_current_date_tool", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -403,6 +402,7 @@ "agent_description": { "_input_type": "MultilineInput", "advanced": true, + "copy_field": false, "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", @@ -410,6 +410,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "multiline": true, "name": "agent_description", @@ -427,6 +428,7 @@ "_input_type": "DropdownInput", "advanced": false, "combobox": false, + "dialog_inputs": {}, "display_name": "Model Provider", "dynamic": false, "info": "The provider of the language model that the agent will use to generate responses.", @@ -439,11 +441,29 @@ "OpenAI", "Custom" ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], "placeholder": "", "real_time_refresh": true, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -460,11 +480,12 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -482,7 +503,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -491,11 +512,13 @@ "dynamic": false, "info": "Should the Agent fix errors when reading user input for better processing?", "list": false, + "list_add_label": "Add More", "name": "handle_parsing_errors", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -510,6 +533,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "name": "input_value", "placeholder": "", @@ -529,11 +553,13 @@ "dynamic": false, "info": "If True, it will output JSON regardless of passing a schema.", "list": false, + "list_add_label": "Add More", "name": "json_mode", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": false @@ -545,11 +571,13 @@ "dynamic": false, "info": "The maximum number of attempts the agent can make to complete its task before it stops.", "list": false, + "list_add_label": "Add More", "name": "max_iterations", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 15 @@ -579,6 +607,7 @@ "dynamic": false, "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", "list": false, + "list_add_label": "Add More", "name": "max_tokens", "placeholder": "", "range_spec": { @@ -590,73 +619,11 @@ "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": "" }, - "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": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -664,11 +631,13 @@ "dynamic": false, "info": "Additional keyword arguments to pass to the model.", "list": false, + "list_add_label": "Add More", "name": "model_kwargs", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_input": true, "type": "dict", "value": {} @@ -677,9 +646,11 @@ "_input_type": "DropdownInput", "advanced": false, "combobox": true, + "dialog_inputs": {}, "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -694,10 +665,13 @@ "gpt-3.5-turbo", "o1" ], + "options_metadata": [], "placeholder": "", + "real_time_refresh": false, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -706,15 +680,17 @@ "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, + "list_add_label": "Add More", "name": "n_messages", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 100 @@ -726,36 +702,17 @@ "dynamic": false, "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", "list": false, + "list_add_label": "Add More", "load_from_db": false, "name": "openai_api_base", "placeholder": "", "required": false, "show": true, "title_case": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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" + "value": "" }, "seed": { "_input_type": "IntInput", @@ -764,109 +721,21 @@ "dynamic": false, "info": "The seed controls the reproducibility of the job.", "list": false, + "list_add_label": "Add More", "name": "seed", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 1 }, - "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": "Finance Agent" - }, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, + "copy_field": false, "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", @@ -874,6 +743,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "multiline": true, "name": "system_prompt", @@ -888,43 +758,32 @@ "value": "You are the chief editor of a prestigious publication known for transforming complex information into clear, engaging content. Review and refine the researcher's document about {topic}.\n\nYour editing process should:\n- Verify and challenge any questionable claims\n- Restructure content for better flow and readability\n- Remove redundancies and unclear statements\n- Add context where needed\n- Ensure balanced coverage of the topic\n- Transform technical language into accessible explanations\n\nMaintain high editorial standards while making the content engaging for an educated general audience. Present the revised version in a clean, well-structured format." }, "temperature": { - "_input_type": "FloatInput", + "_input_type": "SliderInput", "advanced": true, "display_name": "Temperature", "dynamic": false, "info": "", - "list": false, + "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, - "title_case": false, - "trace_as_metadata": true, - "type": "float", - "value": 0.1 - }, - "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, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, "title_case": false, "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" + "type": "slider", + "value": 0.1 }, "timeout": { "_input_type": "IntInput", @@ -954,6 +813,7 @@ "Tool" ], "list": true, + "list_add_label": "Add More", "name": "tools", "placeholder": "", "required": false, @@ -970,11 +830,13 @@ "dynamic": false, "info": "", "list": false, + "list_add_label": "Add More", "name": "verbose", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -987,7 +849,7 @@ }, "dragging": false, "height": 650, - "id": "Agent-xzdFp", + "id": "Agent-qBOQH", "measured": { "height": 650, "width": 320 @@ -1008,7 +870,7 @@ "data": { "description": "Define the agent's instructions, then enter a task to complete using tools.", "display_name": "Analysis & Editor Agent", - "id": "Agent-INg7A", + "id": "Agent-RBaM2", "node": { "base_classes": [ "Message" @@ -1025,34 +887,28 @@ "max_tokens", "model_kwargs", "json_mode", - "output_schema", "model_name", "openai_api_base", "api_key", "temperature", "seed", - "output_parser", + "max_retries", + "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, "icon": "bot", "legacy": false, - "lf_version": "1.0.19.post2", "metadata": {}, + "minimized": false, "output_types": [], "outputs": [ { @@ -1060,8 +916,11 @@ "cache": true, "display_name": "Response", "group_outputs": false, + "hidden": null, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1080,11 +939,13 @@ "dynamic": false, "info": "If true, will add a tool to the agent that returns the current date.", "list": false, + "list_add_label": "Add More", "name": "add_current_date_tool", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -1092,6 +953,7 @@ "agent_description": { "_input_type": "MultilineInput", "advanced": true, + "copy_field": false, "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", @@ -1099,6 +961,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "multiline": true, "name": "agent_description", @@ -1116,6 +979,7 @@ "_input_type": "DropdownInput", "advanced": false, "combobox": false, + "dialog_inputs": {}, "display_name": "Model Provider", "dynamic": false, "info": "The provider of the language model that the agent will use to generate responses.", @@ -1128,11 +992,29 @@ "OpenAI", "Custom" ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], "placeholder": "", "real_time_refresh": true, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1149,11 +1031,12 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -1171,7 +1054,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1180,11 +1063,13 @@ "dynamic": false, "info": "Should the Agent fix errors when reading user input for better processing?", "list": false, + "list_add_label": "Add More", "name": "handle_parsing_errors", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -1199,6 +1084,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "name": "input_value", "placeholder": "", @@ -1218,11 +1104,13 @@ "dynamic": false, "info": "If True, it will output JSON regardless of passing a schema.", "list": false, + "list_add_label": "Add More", "name": "json_mode", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": false @@ -1234,11 +1122,13 @@ "dynamic": false, "info": "The maximum number of attempts the agent can make to complete its task before it stops.", "list": false, + "list_add_label": "Add More", "name": "max_iterations", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 15 @@ -1268,6 +1158,7 @@ "dynamic": false, "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", "list": false, + "list_add_label": "Add More", "name": "max_tokens", "placeholder": "", "range_spec": { @@ -1279,73 +1170,11 @@ "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": "" }, - "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": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -1353,11 +1182,13 @@ "dynamic": false, "info": "Additional keyword arguments to pass to the model.", "list": false, + "list_add_label": "Add More", "name": "model_kwargs", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_input": true, "type": "dict", "value": {} @@ -1366,9 +1197,11 @@ "_input_type": "DropdownInput", "advanced": false, "combobox": true, + "dialog_inputs": {}, "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -1383,10 +1216,13 @@ "gpt-3.5-turbo", "o1" ], + "options_metadata": [], "placeholder": "", + "real_time_refresh": false, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1395,15 +1231,17 @@ "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, + "list_add_label": "Add More", "name": "n_messages", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 100 @@ -1415,36 +1253,17 @@ "dynamic": false, "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", "list": false, + "list_add_label": "Add More", "load_from_db": false, "name": "openai_api_base", "placeholder": "", "required": false, "show": true, "title_case": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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" + "value": "" }, "seed": { "_input_type": "IntInput", @@ -1453,109 +1272,21 @@ "dynamic": false, "info": "The seed controls the reproducibility of the job.", "list": false, + "list_add_label": "Add More", "name": "seed", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 1 }, - "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": "Analysis & Editor Agent" - }, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, + "copy_field": false, "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", @@ -1563,6 +1294,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "multiline": true, "name": "system_prompt", @@ -1577,43 +1309,32 @@ "value": "You are a brilliant comedy writer known for making complex topics entertaining and memorable. Using the editor's refined document about {topic}, create an engaging, humorous blog post.\n\nYour approach should:\n- Find unexpected angles and amusing parallels\n- Use clever wordplay and wit (avoid cheap jokes)\n- Maintain accuracy while being entertaining\n- Include relatable examples and analogies\n- Keep a smart, sophisticated tone\n- Make the topic more approachable through humor\n\nCreate a blog post that makes people laugh while actually teaching them about {topic}. The humor should enhance, not overshadow, the educational value." }, "temperature": { - "_input_type": "FloatInput", + "_input_type": "SliderInput", "advanced": true, "display_name": "Temperature", "dynamic": false, "info": "", - "list": false, + "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, - "title_case": false, - "trace_as_metadata": true, - "type": "float", - "value": 0.1 - }, - "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, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, "title_case": false, "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" + "type": "slider", + "value": 0.1 }, "timeout": { "_input_type": "IntInput", @@ -1643,6 +1364,7 @@ "Tool" ], "list": true, + "list_add_label": "Add More", "name": "tools", "placeholder": "", "required": false, @@ -1659,11 +1381,13 @@ "dynamic": false, "info": "", "list": false, + "list_add_label": "Add More", "name": "verbose", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -1676,7 +1400,7 @@ }, "dragging": false, "height": 650, - "id": "Agent-INg7A", + "id": "Agent-RBaM2", "measured": { "height": 650, "width": 320 @@ -1689,7 +1413,7 @@ "x": 815.1900903820148, "y": -1365.4053932711827 }, - "selected": false, + "selected": true, "type": "genericNode", "width": 320 }, @@ -1697,7 +1421,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-f7d7X", + "id": "Prompt-7Qbz7", "node": { "base_classes": [ "Message" @@ -1811,7 +1535,7 @@ }, "dragging": false, "height": 260, - "id": "Prompt-f7d7X", + "id": "Prompt-7Qbz7", "measured": { "height": 260, "width": 320 @@ -1832,7 +1556,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-d1yBl", + "id": "Prompt-iDIlP", "node": { "base_classes": [ "Message" @@ -1946,7 +1670,7 @@ }, "dragging": false, "height": 260, - "id": "Prompt-d1yBl", + "id": "Prompt-iDIlP", "measured": { "height": 260, "width": 320 @@ -1967,7 +1691,7 @@ "data": { "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", - "id": "Prompt-WNOHC", + "id": "Prompt-m2JmU", "node": { "base_classes": [ "Message" @@ -2130,7 +1854,7 @@ }, "dragging": false, "height": 433, - "id": "Prompt-WNOHC", + "id": "Prompt-m2JmU", "measured": { "height": 433, "width": 320 @@ -2149,7 +1873,7 @@ }, { "data": { - "id": "ChatInput-EXrQ4", + "id": "ChatInput-pauUk", "node": { "base_classes": [ "Message" @@ -2434,7 +2158,7 @@ }, "dragging": false, "height": 234, - "id": "ChatInput-EXrQ4", + "id": "ChatInput-pauUk", "measured": { "height": 234, "width": 320 @@ -2453,7 +2177,7 @@ }, { "data": { - "id": "note-Lit1C", + "id": "note-Hz4pk", "node": { "description": "# Sequential Tasks Agents\n\n## Overview\nThis flow demonstrates how to chain multiple AI agents for comprehensive research and analysis. Each agent specializes in different aspects of the research process, building upon the previous agent's work.\n\n## How to Use the Flow\n\n1. **Input Your Query** 🎯\n - Be specific and clear\n - Include key aspects you want analyzed\n - Examples:\n ```\n Good: \"Should I invest in Tesla (TSLA)? Focus on AI development impact\"\n Bad: \"Tell me about Tesla\"\n ```\n\n2. **Research Agent Process** 🔍\n - Utilizes Tavily Search for comprehensive research\n\n\n3. **Specialized Analysis** 📊\n - Each agent adds unique value:\n ```\n Research Agent → Deep Research & Context\n ↓\n Finance Agent → Data Analysis & Metrics\n ↓\n Editor Agent → Final Synthesis & Report\n ```\n\n4. **Output Format** 📝\n - Structured report\n - Embedded images and charts\n - Data-backed insights\n - Clear recommendations\n\n## Pro Tips\n\n### Query Construction\n- Include specific points of interest\n- Mention required metrics or data points\n- Specify time frames if relevant\n\n### Flow Customization\n- Modify agent prompts for different use cases\n- Add or remove tools as needed\n\n## Common Applications\n- Investment Research\n- Market Analysis\n- Competitive Intelligence\n- Industry Reports\n- Technology Impact Studies\n\n⚡ **Best Practice**: Start with a test query to understand the flow's capabilities before running complex analyses.\n\n---\n*Note: This flow template uses financial analysis as an example but can be adapted for any research-intensive task requiring multiple perspectives and data sources.*", "display_name": "", @@ -2464,10 +2188,10 @@ }, "dragging": false, "height": 800, - "id": "note-Lit1C", + "id": "note-Hz4pk", "measured": { "height": 800, - "width": 601 + "width": 600 }, "position": { "x": -2122.739127560837, @@ -2488,7 +2212,7 @@ }, { "data": { - "id": "note-aqqVW", + "id": "note-2kxI9", "node": { "description": "## What Are Sequential Task Agents?\nA system where multiple AI agents work in sequence, each specializing in specific tasks and passing their output to the next agent in the chain. Think of it as an assembly line where each agent adds value to the final result.\n\n## How It Works\n1. **First Agent** → **Second Agent** → **Third Agent** → **Final Output**\n - Each agent receives input from the previous one\n - Processes and enhances the information\n - Passes refined output forward\n\n## Key Benefits\n- **Specialization**: Each agent focuses on specific tasks\n- **Progressive Refinement**: Information gets enhanced at each step\n- **Structured Output**: Final result combines multiple perspectives\n- **Quality Control**: Each agent validates and improves previous work\n\n## Building Your Own Sequence\n1. **Plan Your Chain**\n - Identify distinct tasks\n - Determine logical order\n - Define input/output requirements\n\n2. **Configure Agents**\n - Give each agent clear instructions\n - Ensure compatible outputs/inputs\n - Set appropriate tools for each agent\n\n3. **Connect the Flow**\n - Link agents in proper order\n - Test data flow between agents\n - Verify final output format\n\n## Example Applications\n- Research → Analysis → Report Writing\n- Data Collection → Processing → Visualization\n- Content Research → Writing → Editing\n- Market Analysis → Financial Review → Investment Advice\n\n⭐ **Pro Tip**: The strength of sequential agents comes from how well they complement each other's capabilities.\n\nThis template uses financial analysis as an example, but you can adapt it for any multi-step process requiring different expertise at each stage.", "display_name": "", @@ -2501,10 +2225,10 @@ }, "dragging": false, "height": 800, - "id": "note-aqqVW", + "id": "note-2kxI9", "measured": { "height": 800, - "width": 601 + "width": 600 }, "position": { "x": -1423.4595108457968, @@ -2527,7 +2251,7 @@ "data": { "description": "Define the agent's instructions, then enter a task to complete using tools.", "display_name": "Researcher Agent", - "id": "Agent-mYTzY", + "id": "Agent-fFCyc", "node": { "base_classes": [ "Message" @@ -2544,34 +2268,28 @@ "max_tokens", "model_kwargs", "json_mode", - "output_schema", "model_name", "openai_api_base", "api_key", "temperature", "seed", - "output_parser", + "max_retries", + "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, "icon": "bot", "legacy": false, - "lf_version": "1.0.19.post2", "metadata": {}, + "minimized": false, "output_types": [], "outputs": [ { @@ -2579,8 +2297,11 @@ "cache": true, "display_name": "Response", "group_outputs": false, + "hidden": null, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -2599,11 +2320,13 @@ "dynamic": false, "info": "If true, will add a tool to the agent that returns the current date.", "list": false, + "list_add_label": "Add More", "name": "add_current_date_tool", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -2611,6 +2334,7 @@ "agent_description": { "_input_type": "MultilineInput", "advanced": true, + "copy_field": false, "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", @@ -2618,6 +2342,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "multiline": true, "name": "agent_description", @@ -2635,6 +2360,7 @@ "_input_type": "DropdownInput", "advanced": false, "combobox": false, + "dialog_inputs": {}, "display_name": "Model Provider", "dynamic": false, "info": "The provider of the language model that the agent will use to generate responses.", @@ -2647,11 +2373,29 @@ "OpenAI", "Custom" ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], "placeholder": "", "real_time_refresh": true, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -2668,11 +2412,12 @@ "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, "type": "str", - "value": "OPENAI_API_KEY" + "value": "" }, "code": { "advanced": true, @@ -2690,7 +2435,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -2699,11 +2444,13 @@ "dynamic": false, "info": "Should the Agent fix errors when reading user input for better processing?", "list": false, + "list_add_label": "Add More", "name": "handle_parsing_errors", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -2718,6 +2465,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "name": "input_value", "placeholder": "", @@ -2737,11 +2485,13 @@ "dynamic": false, "info": "If True, it will output JSON regardless of passing a schema.", "list": false, + "list_add_label": "Add More", "name": "json_mode", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": false @@ -2753,11 +2503,13 @@ "dynamic": false, "info": "The maximum number of attempts the agent can make to complete its task before it stops.", "list": false, + "list_add_label": "Add More", "name": "max_iterations", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 15 @@ -2787,6 +2539,7 @@ "dynamic": false, "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", "list": false, + "list_add_label": "Add More", "name": "max_tokens", "placeholder": "", "range_spec": { @@ -2798,73 +2551,11 @@ "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": "" }, - "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": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -2872,11 +2563,13 @@ "dynamic": false, "info": "Additional keyword arguments to pass to the model.", "list": false, + "list_add_label": "Add More", "name": "model_kwargs", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_input": true, "type": "dict", "value": {} @@ -2885,9 +2578,11 @@ "_input_type": "DropdownInput", "advanced": false, "combobox": true, + "dialog_inputs": {}, "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -2902,10 +2597,13 @@ "gpt-3.5-turbo", "o1" ], + "options_metadata": [], "placeholder": "", + "real_time_refresh": false, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -2914,15 +2612,17 @@ "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, + "list_add_label": "Add More", "name": "n_messages", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 100 @@ -2934,36 +2634,17 @@ "dynamic": false, "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", "list": false, + "list_add_label": "Add More", "load_from_db": false, "name": "openai_api_base", "placeholder": "", "required": false, "show": true, "title_case": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "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" + "value": "" }, "seed": { "_input_type": "IntInput", @@ -2972,109 +2653,21 @@ "dynamic": false, "info": "The seed controls the reproducibility of the job.", "list": false, + "list_add_label": "Add More", "name": "seed", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "int", "value": 1 }, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, + "copy_field": false, "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", @@ -3082,6 +2675,7 @@ "Message" ], "list": false, + "list_add_label": "Add More", "load_from_db": false, "multiline": true, "name": "system_prompt", @@ -3096,43 +2690,32 @@ "value": "You are a helpful assistant that can use tools to answer questions and perform tasks." }, "temperature": { - "_input_type": "FloatInput", + "_input_type": "SliderInput", "advanced": true, "display_name": "Temperature", "dynamic": false, "info": "", - "list": false, + "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, - "title_case": false, - "trace_as_metadata": true, - "type": "float", - "value": 0.1 - }, - "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, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, "title_case": false, "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" + "type": "slider", + "value": 0.1 }, "timeout": { "_input_type": "IntInput", @@ -3162,6 +2745,7 @@ "Tool" ], "list": true, + "list_add_label": "Add More", "name": "tools", "placeholder": "", "required": false, @@ -3178,11 +2762,13 @@ "dynamic": false, "info": "", "list": false, + "list_add_label": "Add More", "name": "verbose", "placeholder": "", "required": false, "show": true, "title_case": false, + "tool_mode": false, "trace_as_metadata": true, "type": "bool", "value": true @@ -3195,7 +2781,7 @@ }, "dragging": false, "height": 650, - "id": "Agent-mYTzY", + "id": "Agent-fFCyc", "measured": { "height": 650, "width": 320 @@ -3214,7 +2800,7 @@ }, { "data": { - "id": "note-VDGf8", + "id": "note-w4VzC", "node": { "description": "# 🔑 Tavily AI Search Needs API Key\n\nYou can get 1000 searches/month free [here](https://tavily.com/) ", "display_name": "", @@ -3227,10 +2813,10 @@ }, "dragging": false, "height": 324, - "id": "note-VDGf8", + "id": "note-w4VzC", "measured": { "height": 324, - "width": 348 + "width": 347 }, "position": { "x": -1152.542145753744, @@ -3251,7 +2837,7 @@ }, { "data": { - "id": "note-lux0a", + "id": "note-3NPhI", "node": { "description": "## Configure the agent by obtaining your OpenAI API key from [platform.openai.com](https://platform.openai.com). Under \"Model Provider\", choose:\n- OpenAI: Default, requires only API key\n- Anthropic/Azure/Groq/NVIDIA/SambaNova: Each requires their own API keys\n- Custom: Use your own model endpoint + authentication\n\nSelect model and input API key before running the flow.", "display_name": "", @@ -3264,10 +2850,10 @@ }, "dragging": false, "height": 324, - "id": "note-lux0a", + "id": "note-3NPhI", "measured": { "height": 324, - "width": 371 + "width": 370 }, "position": { "x": -736.720927923848, @@ -3290,7 +2876,7 @@ "data": { "description": "Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", "display_name": "Yahoo Finance", - "id": "YfinanceComponent-Adjq6", + "id": "YfinanceComponent-8yre9", "node": { "base_classes": [ "Data", @@ -3320,6 +2906,7 @@ "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": null, "method": "to_toolkit", "name": "component_as_tool", @@ -3442,11 +3029,11 @@ "value": "" }, "tools_metadata": { - "_input_type": "TableInput", + "_input_type": "ToolsInput", "advanced": false, - "display_name": "Edit tools", + "display_name": "Actions", "dynamic": false, - "info": "", + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", "is_list": true, "list_add_label": "Add More", "name": "tools_metadata", @@ -3454,110 +3041,28 @@ "real_time_refresh": true, "required": false, "show": true, - "table_icon": "Hammer", - "table_options": { - "block_add": true, - "block_delete": true, - "block_edit": true, - "block_filter": true, - "block_hide": true, - "block_select": true, - "block_sort": true, - "description": "Modify tool names and descriptions to help agents understand when to use each tool.", - "field_parsers": { - "commands": "commands", - "name": [ - "snake_case", - "no_blank" - ] - }, - "hide_options": true - }, - "table_schema": { - "columns": [ - { - "default": "None", - "description": "Specify the name of the tool.", - "disable_edit": false, - "display_name": "Tool Name", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "name", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "Describe the purpose of the tool.", - "disable_edit": false, - "display_name": "Tool Description", - "edit_mode": "popover", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "description", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "The default identifiers for the tools and cannot be changed.", - "disable_edit": true, - "display_name": "Tool Identifiers", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": true, - "name": "tags", - "sortable": false, - "type": "str" - }, - { - "default": true, - "description": "Indicates whether the tool is currently active. Set to True to activate this tool.", - "disable_edit": false, - "display_name": "Enable", - "edit_mode": "popover", - "filterable": true, - "formatter": "boolean", - "hidden": false, - "name": "status", - "sortable": true, - "type": "boolean" - } - ] - }, "title_case": false, "tool_mode": false, "trace_as_metadata": true, - "trigger_icon": "Hammer", - "trigger_text": "", - "type": "table", + "type": "tools", "value": [ { - "description": "fetch_content() - Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", - "name": "YfinanceComponent-fetch_content", + "args": { + "symbol": { + "default": "", + "description": "The stock symbol to retrieve data for (e.g., AAPL, GOOG).", + "title": "Symbol", + "type": "string" + } + }, + "description": "Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", + "display_description": "Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", + "display_name": "fetch_content_dataframe", + "name": "fetch_content_dataframe", + "readonly": false, "status": true, "tags": [ - "YfinanceComponent-fetch_content" - ] - }, - { - "description": "fetch_content_text() - Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", - "name": "YfinanceComponent-fetch_content_text", - "status": true, - "tags": [ - "YfinanceComponent-fetch_content_text" - ] - }, - { - "description": "as_dataframe() - Uses [yfinance](https://pypi.org/project/yfinance/) (unofficial package) to access financial data and market information from Yahoo Finance.", - "name": "YfinanceComponent-as_dataframe", - "status": true, - "tags": [ - "YfinanceComponent-as_dataframe" + "fetch_content_dataframe" ] } ] @@ -3570,9 +3075,9 @@ "type": "YfinanceComponent" }, "dragging": true, - "id": "YfinanceComponent-Adjq6", + "id": "YfinanceComponent-8yre9", "measured": { - "height": 519, + "height": 399, "width": 320 }, "position": { @@ -3584,7 +3089,7 @@ }, { "data": { - "id": "CalculatorComponent-9O7Ap", + "id": "CalculatorComponent-4CJEe", "node": { "base_classes": [ "Data" @@ -3609,13 +3114,17 @@ "output_types": [], "outputs": [ { + "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": null, "method": "to_toolkit", "name": "component_as_tool", + "options": null, "required_inputs": null, "selected": "Tool", + "tool_mode": true, "types": [ "Tool" ], @@ -3668,11 +3177,11 @@ "value": "" }, "tools_metadata": { - "_input_type": "TableInput", + "_input_type": "ToolsInput", "advanced": false, - "display_name": "Edit tools", + "display_name": "Actions", "dynamic": false, - "info": "", + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", "is_list": true, "list_add_label": "Add More", "name": "tools_metadata", @@ -3680,74 +3189,28 @@ "real_time_refresh": true, "required": false, "show": true, - "table_icon": "Hammer", - "table_options": { - "block_add": true, - "block_delete": true, - "block_edit": true, - "block_filter": true, - "block_hide": true, - "block_select": true, - "block_sort": true, - "description": "Modify tool names and descriptions to help agents understand when to use each tool.", - "field_parsers": { - "commands": "commands", - "name": [ - "snake_case", - "no_blank" - ] - }, - "hide_options": true - }, - "table_schema": { - "columns": [ - { - "description": "Specify the name of the tool.", - "disable_edit": false, - "display_name": "Tool Name", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "name": "name", - "sortable": false, - "type": "text" - }, - { - "description": "Describe the purpose of the tool.", - "disable_edit": false, - "display_name": "Tool Description", - "edit_mode": "popover", - "filterable": false, - "formatter": "text", - "name": "description", - "sortable": false, - "type": "text" - }, - { - "description": "The default identifiers for the tools and cannot be changed.", - "disable_edit": true, - "display_name": "Tool Identifiers", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "name": "tags", - "sortable": false, - "type": "text" - } - ] - }, "title_case": false, "tool_mode": false, "trace_as_metadata": true, - "trigger_icon": "Hammer", - "trigger_text": "", - "type": "table", + "type": "tools", "value": [ { - "description": "evaluate_expression() - Perform basic arithmetic operations on a given expression.", - "name": "CalculatorComponent-evaluate_expression", + "args": { + "expression": { + "default": "", + "description": "The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').", + "title": "Expression", + "type": "string" + } + }, + "description": "Perform basic arithmetic operations on a given expression.", + "display_description": "Perform basic arithmetic operations on a given expression.", + "display_name": "evaluate_expression", + "name": "evaluate_expression", + "readonly": false, + "status": true, "tags": [ - "CalculatorComponent-evaluate_expression" + "evaluate_expression" ] } ] @@ -3760,21 +3223,21 @@ "type": "CalculatorComponent" }, "dragging": false, - "id": "CalculatorComponent-9O7Ap", + "id": "CalculatorComponent-4CJEe", "measured": { - "height": 334, + "height": 218, "width": 320 }, "position": { "x": 418.5430081507146, "y": -498.99999708804125 }, - "selected": true, + "selected": false, "type": "genericNode" }, { "data": { - "id": "TavilySearchComponent-6ezaX", + "id": "TavilySearchComponent-tO0qf", "node": { "base_classes": [ "Data", @@ -3808,6 +3271,7 @@ "allows_loop": false, "cache": true, "display_name": "Toolset", + "group_outputs": false, "hidden": null, "method": "to_toolkit", "name": "component_as_tool", @@ -3831,7 +3295,7 @@ "dynamic": false, "info": "Your Tavily API Key.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -3839,7 +3303,7 @@ "show": true, "title_case": false, "type": "str", - "value": "TAVILY_API_KEY" + "value": "" }, "chunks_per_source": { "_input_type": "IntInput", @@ -4084,11 +3548,11 @@ "type": "str" }, "tools_metadata": { - "_input_type": "TableInput", + "_input_type": "ToolsInput", "advanced": false, - "display_name": "Edit tools", + "display_name": "Actions", "dynamic": false, - "info": "", + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", "is_list": true, "list_add_label": "Add More", "name": "tools_metadata", @@ -4096,100 +3560,28 @@ "real_time_refresh": true, "required": false, "show": true, - "table_icon": "Hammer", - "table_options": { - "block_add": true, - "block_delete": true, - "block_edit": true, - "block_filter": true, - "block_hide": true, - "block_select": true, - "block_sort": true, - "description": "Modify tool names and descriptions to help agents understand when to use each tool.", - "field_parsers": { - "commands": "commands", - "name": [ - "snake_case", - "no_blank" - ] - }, - "hide_options": true - }, - "table_schema": { - "columns": [ - { - "default": "None", - "description": "Specify the name of the tool.", - "disable_edit": false, - "display_name": "Tool Name", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "name", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "Describe the purpose of the tool.", - "disable_edit": false, - "display_name": "Tool Description", - "edit_mode": "popover", - "filterable": false, - "formatter": "text", - "hidden": false, - "name": "description", - "sortable": false, - "type": "str" - }, - { - "default": "None", - "description": "The default identifiers for the tools and cannot be changed.", - "disable_edit": true, - "display_name": "Tool Identifiers", - "edit_mode": "inline", - "filterable": false, - "formatter": "text", - "hidden": true, - "name": "tags", - "sortable": false, - "type": "str" - }, - { - "default": true, - "description": "Indicates whether the tool is currently active. Set to True to activate this tool.", - "disable_edit": false, - "display_name": "Enable", - "edit_mode": "popover", - "filterable": true, - "formatter": "boolean", - "hidden": false, - "name": "status", - "sortable": true, - "type": "boolean" - } - ] - }, "title_case": false, "tool_mode": false, "trace_as_metadata": true, - "trigger_icon": "Hammer", - "trigger_text": "", - "type": "table", + "type": "tools", "value": [ { - "description": "fetch_content(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", - "name": "TavilySearchComponent-fetch_content", + "args": { + "query": { + "default": "", + "description": "The search query you want to execute with Tavily.", + "title": "Query", + "type": "string" + } + }, + "description": "**Tavily Search** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", + "display_description": "**Tavily Search** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", + "display_name": "fetch_content_dataframe", + "name": "fetch_content_dataframe", + "readonly": false, + "status": true, "tags": [ - "TavilySearchComponent-fetch_content" - ] - }, - { - "description": "fetch_content_text(api_key: Message) - **Tavily AI** is a search engine optimized for LLMs and RAG, aimed at efficient, quick, and persistent search results.", - "name": "TavilySearchComponent-fetch_content_text", - "tags": [ - "TavilySearchComponent-fetch_content_text" + "fetch_content_dataframe" ] } ] @@ -4225,9 +3617,9 @@ "type": "TavilySearchComponent" }, "dragging": false, - "id": "TavilySearchComponent-6ezaX", + "id": "TavilySearchComponent-tO0qf", "measured": { - "height": 437, + "height": 316, "width": 320 }, "position": { @@ -4239,7 +3631,7 @@ }, { "data": { - "id": "ChatOutput-rF4Qx", + "id": "ChatOutput-l6yiS", "node": { "base_classes": [ "Message" @@ -4535,9 +3927,9 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-rF4Qx", + "id": "ChatOutput-l6yiS", "measured": { - "height": 66, + "height": 48, "width": 192 }, "position": { @@ -4549,16 +3941,16 @@ } ], "viewport": { - "x": 777.2369417602284, - "y": 881.5715494830567, - "zoom": 0.37106613302179997 + "x": 347.4165333163444, + "y": 1163.7663746258074, + "zoom": 0.6495626253324138 } }, "description": "This Agent is designed to systematically execute a series of tasks following a meticulously predefined sequence. By adhering to this structured order, the Agent ensures that each task is completed efficiently and effectively, optimizing overall performance and maintaining a high level of accuracy.", "endpoint_name": null, - "id": "98e71965-2948-4541-90cc-15352236491c", + "id": "38180cab-1b43-4ecf-b7ba-67afbb95de79", "is_component": false, - "last_tested_version": "1.2.0", + "last_tested_version": "1.4.3", "name": "Sequential Tasks Agents", "tags": [ "assistants", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json index 9226d1428..7d66e294e 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json @@ -1,69 +1,13 @@ { "data": { "edges": [ - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "CalculatorComponent", - "id": "CalculatorComponent-Sp3Ca", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-xD3uW", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "xy-edge__CalculatorComponent-Sp3Ca{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-Sp3Caœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-xD3uW{œfieldNameœ:œtoolsœ,œidœ:œAgent-xD3uWœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "CalculatorComponent-Sp3Ca", - "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-Sp3Caœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-xD3uW", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-xD3uWœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-S6AhV", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-xD3uW", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "xy-edge__ChatInput-S6AhV{œdataTypeœ:œChatInputœ,œidœ:œChatInput-S6AhVœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-xD3uW{œfieldNameœ:œinput_valueœ,œidœ:œAgent-xD3uWœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-S6AhV", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-S6AhVœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-xD3uW", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-xD3uWœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" - }, { "animated": false, "className": "", "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-xD3uW", + "id": "Agent-D0Kx2", "name": "response", "output_types": [ "Message" @@ -71,7 +15,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-WciiI", + "id": "ChatOutput-yhCn0", "inputTypes": [ "Data", "DataFrame", @@ -80,20 +24,20 @@ "type": "other" } }, - "id": "xy-edge__Agent-xD3uW{œdataTypeœ:œAgentœ,œidœ:œAgent-xD3uWœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-WciiI{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-WciiIœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-Agent-D0Kx2{œdataTypeœ:œAgentœ,œidœ:œAgent-D0Kx2œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-yhCn0{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-yhCn0œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "Agent-xD3uW", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-xD3uWœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-WciiI", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-WciiIœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" + "source": "Agent-D0Kx2", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-D0Kx2œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-yhCn0", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-yhCn0œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" }, { "animated": false, "className": "", "data": { "sourceHandle": { - "dataType": "URLComponent", - "id": "URLComponent-6fRXe", + "dataType": "CalculatorComponent", + "id": "CalculatorComponent-hMbFw", "name": "component_as_tool", "output_types": [ "Tool" @@ -101,25 +45,80 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-xD3uW", + "id": "Agent-D0Kx2", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__URLComponent-6fRXe{œdataTypeœ:œURLComponentœ,œidœ:œURLComponent-6fRXeœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-xD3uW{œfieldNameœ:œtoolsœ,œidœ:œAgent-xD3uWœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-CalculatorComponent-hMbFw{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-hMbFwœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-D0Kx2{œfieldNameœ:œtoolsœ,œidœ:œAgent-D0Kx2œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "URLComponent-6fRXe", - "sourceHandle": "{œdataTypeœ: œURLComponentœ, œidœ: œURLComponent-6fRXeœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-xD3uW", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-xD3uWœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "CalculatorComponent-hMbFw", + "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-hMbFwœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-D0Kx2", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-D0Kx2œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-iPUSx", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-D0Kx2", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-iPUSx{œdataTypeœ:œChatInputœ,œidœ:œChatInput-iPUSxœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-D0Kx2{œfieldNameœ:œinput_valueœ,œidœ:œAgent-D0Kx2œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-iPUSx", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-iPUSxœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-D0Kx2", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-D0Kx2œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "animated": false, + "data": { + "sourceHandle": { + "dataType": "URLComponent", + "id": "URLComponent-TpTHB", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-D0Kx2", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "xy-edge__URLComponent-TpTHB{œdataTypeœ:œURLComponentœ,œidœ:œURLComponent-TpTHBœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-D0Kx2{œfieldNameœ:œtoolsœ,œidœ:œAgent-D0Kx2œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "selected": false, + "source": "URLComponent-TpTHB", + "sourceHandle": "{œdataTypeœ: œURLComponentœ, œidœ: œURLComponent-TpTHBœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-D0Kx2", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-D0Kx2œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "note-ukwn1", + "id": "note-28UlV", "node": { "description": "# 📖 README\nRun an Agent with URL and Calculator tools available for its use. \nThe Agent decides which tool to use to solve a problem.\n## Quick start\n\n1. Add your OpenAI API key to the Agent.\n2. Open the Playground and chat with the Agent. Request some information about a recipe, and then ask to add two numbers together. In the responses, the Agent will use different tools to solve different problems.\n\n## Next steps\nConnect more tools to the Agent to create your perfect assistant.\n\nFor more, see the [Langflow docs](https://docs.langflow.org/agents-tool-calling-agent-component).", "display_name": "", @@ -131,21 +130,21 @@ "type": "note" }, "dragging": false, - "id": "note-ukwn1", + "id": "note-28UlV", "measured": { "height": 630, "width": 575 }, "position": { - "x": 775.5268622081468, - "y": 27.927425537464444 + "x": 637.5791433882063, + "y": 32.76769637325184 }, "selected": false, "type": "noteNode" }, { "data": { - "id": "note-sQfYZ", + "id": "note-2JuVK", "node": { "description": "### 💡 Add your OpenAI API key here👇", "display_name": "", @@ -156,22 +155,21 @@ }, "type": "note" }, - "dragging": false, - "id": "note-sQfYZ", + "id": "note-2JuVK", "measured": { "height": 324, "width": 324 }, "position": { - "x": 1758.8741678279712, - "y": 184.362412184038 + "x": 1648.6876745095624, + "y": 253.8646618156497 }, "selected": false, "type": "noteNode" }, { "data": { - "id": "CalculatorComponent-Sp3Ca", + "id": "CalculatorComponent-hMbFw", "node": { "base_classes": [ "Data" @@ -191,7 +189,7 @@ "icon": "calculator", "key": "CalculatorComponent", "legacy": false, - "lf_version": "1.4.3", + "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -305,9 +303,9 @@ "type": "CalculatorComponent" }, "dragging": false, - "id": "CalculatorComponent-Sp3Ca", + "id": "CalculatorComponent-hMbFw", "measured": { - "height": 217, + "height": 218, "width": 320 }, "position": { @@ -319,7 +317,7 @@ }, { "data": { - "id": "ChatInput-S6AhV", + "id": "ChatInput-iPUSx", "node": { "base_classes": [ "Message" @@ -347,7 +345,6 @@ "icon": "MessagesSquare", "key": "ChatInput", "legacy": false, - "lf_version": "1.4.3", "metadata": {}, "minimized": true, "output_types": [], @@ -620,7 +617,7 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-S6AhV", + "id": "ChatInput-iPUSx", "measured": { "height": 48, "width": 192 @@ -634,7 +631,7 @@ }, { "data": { - "id": "ChatOutput-WciiI", + "id": "ChatOutput-yhCn0", "node": { "base_classes": [ "Message" @@ -663,7 +660,6 @@ "icon": "MessagesSquare", "key": "ChatOutput", "legacy": false, - "lf_version": "1.4.3", "metadata": {}, "minimized": true, "output_types": [], @@ -930,7 +926,7 @@ "showNode": false, "type": "ChatOutput" }, - "id": "ChatOutput-WciiI", + "id": "ChatOutput-yhCn0", "measured": { "height": 48, "width": 192 @@ -944,13 +940,12 @@ }, { "data": { - "id": "Agent-xD3uW", + "id": "Agent-D0Kx2", "node": { "base_classes": [ "Message" ], "beta": false, - "category": "agents", "conditional_paths": [], "custom_fields": {}, "description": "Define the agent's instructions, then enter a task to complete using tools.", @@ -970,29 +965,18 @@ "max_retries", "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "mode", - "message", - "memory", - "sender_type", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, "icon": "bot", - "key": "Agent", "legacy": false, - "lf_version": "1.4.3", "metadata": {}, "minimized": false, "output_types": [], @@ -1002,6 +986,7 @@ "cache": true, "display_name": "Response", "group_outputs": false, + "hidden": null, "method": "message_response", "name": "response", "options": null, @@ -1015,7 +1000,6 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -1072,41 +1056,25 @@ "input_types": [], "name": "agent_llm", "options": [ - "Amazon Bedrock", "Anthropic", - "Azure OpenAI", "Google Generative AI", "Groq", - "NVIDIA", "OpenAI", - "SambaNova", "Custom" ], "options_metadata": [ - { - "icon": "Amazon" - }, { "icon": "Anthropic" }, - { - "icon": "Azure" - }, { "icon": "GoogleGenerativeAI" }, { "icon": "Groq" }, - { - "icon": "NVIDIA" - }, { "icon": "OpenAI" }, - { - "icon": "SambaNova" - }, { "icon": "brain" } @@ -1156,7 +1124,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1277,70 +1245,6 @@ "type": "int", "value": "" }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "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": true, - "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" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -1367,6 +1271,7 @@ "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -1391,20 +1296,20 @@ "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4o" + "value": "gpt-4.1" }, "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, "list_add_label": "Add More", "name": "n_messages", "placeholder": "", "required": false, - "show": false, + "show": true, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -1430,30 +1335,6 @@ "type": "str", "value": "" }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, "seed": { "_input_type": "IntInput", "advanced": true, @@ -1472,100 +1353,6 @@ "type": "int", "value": 1 }, - "sender": { - "_input_type": "MessageTextInput", - "advanced": true, - "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.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": false, - "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, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, @@ -1619,31 +1406,6 @@ "type": "slider", "value": 0.1 }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" - }, "timeout": { "_input_type": "IntInput", "advanced": true, @@ -1703,25 +1465,26 @@ }, "tool_mode": false }, + "selected_output": "response", "showNode": true, "type": "Agent" }, "dragging": false, - "id": "Agent-xD3uW", + "id": "Agent-D0Kx2", "measured": { - "height": 591, + "height": 594, "width": 320 }, "position": { - "x": 1763.0750031786254, - "y": 232.97801992415862 + "x": 1641.6239626366948, + "y": 301.10345101561927 }, - "selected": false, + "selected": true, "type": "genericNode" }, { "data": { - "id": "URLComponent-6fRXe", + "id": "URLComponent-TpTHB", "node": { "base_classes": [ "DataFrame", @@ -1752,7 +1515,6 @@ "icon": "layout-template", "key": "URLComponent", "legacy": false, - "lf_version": "1.4.3", "metadata": {}, "minimized": false, "output_types": [], @@ -2104,28 +1866,28 @@ "type": "URLComponent" }, "dragging": false, - "id": "URLComponent-6fRXe", + "id": "URLComponent-TpTHB", "measured": { - "height": 289, + "height": 290, "width": 320 }, "position": { - "x": 1388.440925896035, - "y": 2.4339723656417362 + "x": 1241.645826777893, + "y": -34.70663041492506 }, - "selected": true, + "selected": false, "type": "genericNode" } ], "viewport": { - "x": -398.05374665521265, - "y": 135.56417788603605, - "zoom": 0.5899089629086188 + "x": -562.0961577584201, + "y": 188.68156067492384, + "zoom": 0.8264000374576776 } }, "description": "A simple but powerful starter agent.", "endpoint_name": null, - "id": "907853a5-ae9a-4636-b629-4c44cfaf6b85", + "id": "0209ae03-677e-4315-b80a-0d90b3e12cb5", "is_component": false, "last_tested_version": "1.4.3", "name": "Simple Agent", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json index 7297b43cd..b27a9fc6e 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "ApifyActors", - "id": "ApifyActors-I9HDQ", + "id": "ApifyActors-Zrjnz", "name": "tool", "output_types": [ "Tool" @@ -15,19 +15,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-wmQQE", + "id": "Agent-0vMrI", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__ApifyActors-I9HDQ{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-I9HDQœ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-wmQQE{œfieldNameœ:œtoolsœ,œidœ:œAgent-wmQQEœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-ApifyActors-Zrjnz{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-Zrjnzœ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-0vMrI{œfieldNameœ:œtoolsœ,œidœ:œAgent-0vMrIœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "ApifyActors-I9HDQ", - "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-I9HDQœ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-wmQQE", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-wmQQEœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "ApifyActors-Zrjnz", + "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-Zrjnzœ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-0vMrI", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-0vMrIœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -35,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "ApifyActors", - "id": "ApifyActors-maVx2", + "id": "ApifyActors-8WoKJ", "name": "tool", "output_types": [ "Tool" @@ -43,19 +43,47 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-wmQQE", + "id": "Agent-0vMrI", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__ApifyActors-maVx2{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-maVx2œ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-wmQQE{œfieldNameœ:œtoolsœ,œidœ:œAgent-wmQQEœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-ApifyActors-8WoKJ{œdataTypeœ:œApifyActorsœ,œidœ:œApifyActors-8WoKJœ,œnameœ:œtoolœ,œoutput_typesœ:[œToolœ]}-Agent-0vMrI{œfieldNameœ:œtoolsœ,œidœ:œAgent-0vMrIœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "ApifyActors-maVx2", - "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-maVx2œ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-wmQQE", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-wmQQEœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "ApifyActors-8WoKJ", + "sourceHandle": "{œdataTypeœ: œApifyActorsœ, œidœ: œApifyActors-8WoKJœ, œnameœ: œtoolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-0vMrI", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-0vMrIœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "ChatInput", + "id": "ChatInput-RBrnT", + "name": "message", + "output_types": [ + "Message" + ] + }, + "targetHandle": { + "fieldName": "input_value", + "id": "Agent-0vMrI", + "inputTypes": [ + "Message" + ], + "type": "str" + } + }, + "id": "reactflow__edge-ChatInput-RBrnT{œdataTypeœ:œChatInputœ,œidœ:œChatInput-RBrnTœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-0vMrI{œfieldNameœ:œinput_valueœ,œidœ:œAgent-0vMrIœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "selected": false, + "source": "ChatInput-RBrnT", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-RBrnTœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-0vMrI", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-0vMrIœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -63,7 +91,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-wmQQE", + "id": "Agent-0vMrI", "name": "response", "output_types": [ "Message" @@ -71,7 +99,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-5yecv", + "id": "ChatOutput-Lgpwq", "inputTypes": [ "Data", "DataFrame", @@ -80,45 +108,18 @@ "type": "other" } }, - "id": "xy-edge__Agent-wmQQE{œdataTypeœ:œAgentœ,œidœ:œAgent-wmQQEœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-5yecv{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-5yecvœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-Agent-0vMrI{œdataTypeœ:œAgentœ,œidœ:œAgent-0vMrIœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-Lgpwq{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-Lgpwqœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œotherœ}", "selected": false, - "source": "Agent-wmQQE", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-wmQQEœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-5yecv", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-5yecvœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "data": { - "sourceHandle": { - "dataType": "ChatInput", - "id": "ChatInput-amkkr", - "name": "message", - "output_types": [ - "Message" - ] - }, - "targetHandle": { - "fieldName": "input_value", - "id": "Agent-wmQQE", - "inputTypes": [ - "Message" - ], - "type": "str" - } - }, - "id": "xy-edge__ChatInput-amkkr{œdataTypeœ:œChatInputœ,œidœ:œChatInput-amkkrœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-wmQQE{œfieldNameœ:œinput_valueœ,œidœ:œAgent-wmQQEœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", - "selected": false, - "source": "ChatInput-amkkr", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-amkkrœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-wmQQE", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-wmQQEœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-0vMrI", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-0vMrIœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-Lgpwq", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-Lgpwqœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "ApifyActors-I9HDQ", + "id": "ApifyActors-8WoKJ", "node": { "base_classes": [ "Data", @@ -205,7 +206,7 @@ "dynamic": false, "info": "The API token for the Apify account.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "apify_token", "password": true, "placeholder": "", @@ -307,9 +308,9 @@ "type": "ApifyActors" }, "dragging": false, - "id": "ApifyActors-I9HDQ", + "id": "ApifyActors-8WoKJ", "measured": { - "height": 523, + "height": 526, "width": 320 }, "position": { @@ -321,7 +322,7 @@ }, { "data": { - "id": "ApifyActors-maVx2", + "id": "ApifyActors-Zrjnz", "node": { "base_classes": [ "Data", @@ -408,7 +409,7 @@ "dynamic": false, "info": "The API token for the Apify account.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "apify_token", "password": true, "placeholder": "", @@ -510,9 +511,9 @@ "type": "ApifyActors" }, "dragging": false, - "id": "ApifyActors-maVx2", + "id": "ApifyActors-Zrjnz", "measured": { - "height": 523, + "height": 526, "width": 320 }, "position": { @@ -524,7 +525,7 @@ }, { "data": { - "id": "note-xssJa", + "id": "note-do2Nq", "node": { "description": "### 💡 Add your Apify API key here ", "display_name": "", @@ -536,7 +537,7 @@ "type": "note" }, "dragging": false, - "id": "note-xssJa", + "id": "note-do2Nq", "measured": { "height": 324, "width": 324 @@ -550,7 +551,7 @@ }, { "data": { - "id": "note-TeGrW", + "id": "note-7z6Er", "node": { "description": "### 💡 Add your Apify API key here ", "display_name": "", @@ -563,7 +564,7 @@ }, "dragging": false, "height": 324, - "id": "note-TeGrW", + "id": "note-7z6Er", "measured": { "height": 324, "width": 324 @@ -579,7 +580,7 @@ }, { "data": { - "id": "note-6PTdf", + "id": "note-NZDOa", "node": { "description": "# Social Media Agent\n\nExtract data with **Apify Actors** and analyze the data with an **Agent**.\n\n## Prerequisites\n\n* An [Apify API token](https://docs.apify.com/platform/integrations/api#api-token)\n* An [OpenAI API key](https://platform.openai.com/)\n\n## Quickstart\n\n1. Enter your **Apify** API token in the **Apify Token** fields of the **Apify Actors** components. \n2. Enter your **OpenAI** API token in the **OpenAI API Key** field of the **Agent** component.\n3. Open the **Playground** and chat with the agent. For example, task it with retrieving a profile bio and the latest video by using this prompt: \n ```\n Find the TikTok profile of the company OpenAI using Google search, then show me the profile bio and their latest video.\n ```", "display_name": "", @@ -592,7 +593,7 @@ }, "dragging": false, "height": 657, - "id": "note-6PTdf", + "id": "note-NZDOa", "measured": { "height": 657, "width": 524 @@ -608,7 +609,7 @@ }, { "data": { - "id": "ChatInput-amkkr", + "id": "ChatInput-RBrnT", "node": { "base_classes": [ "Message" @@ -634,7 +635,7 @@ "frozen": false, "icon": "MessagesSquare", "legacy": false, - "lf_version": "1.4.3", + "lf_version": "1.4.2", "metadata": {}, "minimized": true, "output_types": [], @@ -905,7 +906,7 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-amkkr", + "id": "ChatInput-RBrnT", "measured": { "height": 48, "width": 192 @@ -919,7 +920,7 @@ }, { "data": { - "id": "ChatOutput-5yecv", + "id": "ChatOutput-Lgpwq", "node": { "base_classes": [ "Message" @@ -1213,7 +1214,7 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-5yecv", + "id": "ChatOutput-Lgpwq", "measured": { "height": 48, "width": 192 @@ -1227,7 +1228,7 @@ }, { "data": { - "id": "note-psyK5", + "id": "note-1Ws1d", "node": { "description": "### 💡 Add your OpenAI API key here ", "display_name": "", @@ -1239,7 +1240,7 @@ "type": "note" }, "dragging": false, - "id": "note-psyK5", + "id": "note-1Ws1d", "measured": { "height": 324, "width": 324 @@ -1253,13 +1254,12 @@ }, { "data": { - "id": "Agent-wmQQE", + "id": "Agent-0vMrI", "node": { "base_classes": [ "Message" ], "beta": false, - "category": "agents", "conditional_paths": [], "custom_fields": {}, "description": "Define the agent's instructions, then enter a task to complete using tools.", @@ -1279,27 +1279,17 @@ "max_retries", "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "mode", - "message", - "memory", - "sender_type", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, "icon": "bot", - "key": "Agent", "legacy": false, "metadata": {}, "minimized": false, @@ -1310,6 +1300,7 @@ "cache": true, "display_name": "Response", "group_outputs": false, + "hidden": null, "method": "message_response", "name": "response", "options": null, @@ -1323,7 +1314,6 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -1421,7 +1411,7 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", @@ -1448,7 +1438,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1569,70 +1559,6 @@ "type": "int", "value": "" }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "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": true, - "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" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -1659,6 +1585,7 @@ "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -1683,20 +1610,20 @@ "tool_mode": false, "trace_as_metadata": true, "type": "str", - "value": "gpt-4o" + "value": "gpt-4.1" }, "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, "list_add_label": "Add More", "name": "n_messages", "placeholder": "", "required": false, - "show": false, + "show": true, "title_case": false, "tool_mode": false, "trace_as_metadata": true, @@ -1722,30 +1649,6 @@ "type": "str", "value": "" }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, "seed": { "_input_type": "IntInput", "advanced": true, @@ -1764,100 +1667,6 @@ "type": "int", "value": 1 }, - "sender": { - "_input_type": "MessageTextInput", - "advanced": true, - "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.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": false, - "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, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, @@ -1911,31 +1720,6 @@ "type": "slider", "value": 0.1 }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" - }, "timeout": { "_input_type": "IntInput", "advanced": true, @@ -1995,32 +1779,33 @@ }, "tool_mode": false }, + "selected_output": "response", "showNode": true, "type": "Agent" }, "dragging": false, - "id": "Agent-wmQQE", + "id": "Agent-0vMrI", "measured": { - "height": 591, + "height": 594, "width": 320 }, "position": { - "x": 1040.7328325813182, - "y": 309.2404087611358 + "x": 1023.5315500182937, + "y": 280.6548808097231 }, "selected": true, "type": "genericNode" } ], "viewport": { - "x": -11.680210843338386, - "y": 7.902598790141155, - "zoom": 0.5704013010733382 + "x": 281.02651297047544, + "y": 209.9438393445942, + "zoom": 0.6868478679218015 } }, "description": "Utilize Apify Actors as agent tools to search and analyze social media profiles.", "endpoint_name": null, - "id": "fc6be8ff-289b-43c5-bb7a-35274b5930af", + "id": "6c13c359-1078-452d-acdb-863aedd98e23", "is_component": false, "last_tested_version": "1.4.3", "name": "Social Media Agent", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json index b1c57f885..2a3bd9dc4 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json @@ -1,13 +1,41 @@ { "data": { "edges": [ + { + "animated": false, + "className": "", + "data": { + "sourceHandle": { + "dataType": "SearchComponent", + "id": "SearchComponent-vbaqY", + "name": "component_as_tool", + "output_types": [ + "Tool" + ] + }, + "targetHandle": { + "fieldName": "tools", + "id": "Agent-c2dqD", + "inputTypes": [ + "Tool" + ], + "type": "other" + } + }, + "id": "reactflow__edge-SearchComponent-vbaqY{œdataTypeœ:œSearchComponentœ,œidœ:œSearchComponent-vbaqYœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-c2dqD{œfieldNameœ:œtoolsœ,œidœ:œAgent-c2dqDœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "selected": false, + "source": "SearchComponent-vbaqY", + "sourceHandle": "{œdataTypeœ: œSearchComponentœ, œidœ: œSearchComponent-vbaqYœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-c2dqD", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-c2dqDœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + }, { "animated": false, "className": "", "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-GQzN9", + "id": "ChatInput-rc4oD", "name": "message", "output_types": [ "Message" @@ -15,19 +43,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-SVMdS", + "id": "Agent-c2dqD", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-GQzN9{œdataTypeœ:œChatInputœ,œidœ:œChatInput-GQzN9œ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-SVMdS{œfieldNameœ:œinput_valueœ,œidœ:œAgent-SVMdSœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-rc4oD{œdataTypeœ:œChatInputœ,œidœ:œChatInput-rc4oDœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-Agent-c2dqD{œfieldNameœ:œinput_valueœ,œidœ:œAgent-c2dqDœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-GQzN9", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-GQzN9œ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-SVMdS", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-SVMdSœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-rc4oD", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-rc4oDœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-c2dqD", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-c2dqDœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -35,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-SVMdS", + "id": "Agent-c2dqD", "name": "response", "output_types": [ "Message" @@ -43,19 +71,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-Huf0O", + "id": "Agent-kfSsu", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Agent-SVMdS{œdataTypeœ:œAgentœ,œidœ:œAgent-SVMdSœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-Huf0O{œfieldNameœ:œinput_valueœ,œidœ:œAgent-Huf0Oœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-c2dqD{œdataTypeœ:œAgentœ,œidœ:œAgent-c2dqDœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-kfSsu{œfieldNameœ:œinput_valueœ,œidœ:œAgent-kfSsuœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-SVMdS", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-SVMdSœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-Huf0O", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-Huf0Oœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-c2dqD", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-c2dqDœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-kfSsu", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-kfSsuœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -63,7 +91,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-Huf0O", + "id": "Agent-kfSsu", "name": "response", "output_types": [ "Message" @@ -71,19 +99,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-jiGgJ", + "id": "Agent-fMEDP", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Agent-Huf0O{œdataTypeœ:œAgentœ,œidœ:œAgent-Huf0Oœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-jiGgJ{œfieldNameœ:œinput_valueœ,œidœ:œAgent-jiGgJœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-kfSsu{œdataTypeœ:œAgentœ,œidœ:œAgent-kfSsuœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-Agent-fMEDP{œfieldNameœ:œinput_valueœ,œidœ:œAgent-fMEDPœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-Huf0O", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-Huf0Oœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-jiGgJ", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-jiGgJœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-kfSsu", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-kfSsuœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-fMEDP", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-fMEDPœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -91,7 +119,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-jiGgJ", + "id": "Agent-fMEDP", "name": "response", "output_types": [ "Message" @@ -99,7 +127,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-CvvO2", + "id": "ChatOutput-HiCTg", "inputTypes": [ "Data", "DataFrame", @@ -108,19 +136,20 @@ "type": "str" } }, - "id": "reactflow__edge-Agent-jiGgJ{œdataTypeœ:œAgentœ,œidœ:œAgent-jiGgJœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-CvvO2{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-CvvO2œ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-fMEDP{œdataTypeœ:œAgentœ,œidœ:œAgent-fMEDPœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-HiCTg{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-HiCTgœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-jiGgJ", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-jiGgJœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-CvvO2", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-CvvO2œ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-fMEDP", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-fMEDPœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-HiCTg", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-HiCTgœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, + "className": "", "data": { "sourceHandle": { - "dataType": "SearchComponent", - "id": "SearchComponent-3nVDj", + "dataType": "URL", + "id": "URL-sFiMQ", "name": "component_as_tool", "output_types": [ "Tool" @@ -128,52 +157,27 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-SVMdS", + "id": "Agent-kfSsu", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__SearchComponent-3nVDj{œdataTypeœ:œSearchComponentœ,œidœ:œSearchComponent-3nVDjœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-SVMdS{œfieldNameœ:œtoolsœ,œidœ:œAgent-SVMdSœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-URL-sFiMQ{œdataTypeœ:œURLœ,œidœ:œURL-sFiMQœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-kfSsu{œfieldNameœ:œtoolsœ,œidœ:œAgent-kfSsuœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "SearchComponent-3nVDj", - "sourceHandle": "{œdataTypeœ: œSearchComponentœ, œidœ: œSearchComponent-3nVDjœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-SVMdS", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-SVMdSœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "URL-sFiMQ", + "sourceHandle": "{œdataTypeœ: œURLœ, œidœ: œURL-sFiMQœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-kfSsu", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-kfSsuœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, - "data": { - "sourceHandle": { - "dataType": "URLComponent", - "id": "URLComponent-8bgTS", - "name": "component_as_tool", - "output_types": [ - "Tool" - ] - }, - "targetHandle": { - "fieldName": "tools", - "id": "Agent-Huf0O", - "inputTypes": [ - "Tool" - ], - "type": "other" - } - }, - "id": "xy-edge__URLComponent-8bgTS{œdataTypeœ:œURLComponentœ,œidœ:œURLComponent-8bgTSœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-Huf0O{œfieldNameœ:œtoolsœ,œidœ:œAgent-Huf0Oœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "selected": false, - "source": "URLComponent-8bgTS", - "sourceHandle": "{œdataTypeœ: œURLComponentœ, œidœ: œURLComponent-8bgTSœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-Huf0O", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-Huf0Oœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" - }, - { + "className": "", "data": { "sourceHandle": { "dataType": "CalculatorComponent", - "id": "CalculatorComponent-JKeHR", + "id": "CalculatorComponent-oWut2", "name": "component_as_tool", "output_types": [ "Tool" @@ -181,24 +185,25 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-jiGgJ", + "id": "Agent-fMEDP", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "xy-edge__CalculatorComponent-JKeHR{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-JKeHRœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-jiGgJ{œfieldNameœ:œtoolsœ,œidœ:œAgent-jiGgJœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", - "source": "CalculatorComponent-JKeHR", - "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-JKeHRœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-jiGgJ", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-jiGgJœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "id": "reactflow__edge-CalculatorComponent-oWut2{œdataTypeœ:œCalculatorComponentœ,œidœ:œCalculatorComponent-oWut2œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-fMEDP{œfieldNameœ:œtoolsœ,œidœ:œAgent-fMEDPœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "selected": false, + "source": "CalculatorComponent-oWut2", + "sourceHandle": "{œdataTypeœ: œCalculatorComponentœ, œidœ: œCalculatorComponent-oWut2œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-fMEDP", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-fMEDPœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "ChatInput-GQzN9", + "id": "ChatInput-rc4oD", "node": { "base_classes": [ "Message" @@ -472,7 +477,7 @@ }, "dragging": false, "height": 262, - "id": "ChatInput-GQzN9", + "id": "ChatInput-rc4oD", "measured": { "height": 262, "width": 360 @@ -493,7 +498,7 @@ "data": { "description": "Display a chat message in the Playground.", "display_name": "Chat Output", - "id": "ChatOutput-CvvO2", + "id": "ChatOutput-HiCTg", "node": { "base_classes": [ "Message" @@ -776,7 +781,7 @@ }, "dragging": false, "height": 262, - "id": "ChatOutput-CvvO2", + "id": "ChatOutput-HiCTg", "measured": { "height": 262, "width": 360 @@ -795,7 +800,7 @@ }, { "data": { - "id": "note-CQDFw", + "id": "note-RAam9", "node": { "description": "# Travel Planning Agents \n\nThe travel planning system is a smart setup that uses several specialized \"agents\" to help plan incredible trips. Imagine each agent as a travel expert focusing on a part of your journey. Here's how it works:\n\n- **User-Friendly Start:** You start by telling the system about your travel needs—where you want to go and what you love to do.\n\n- **Data Collection:** The agents uses its tools to gather current info about various destinations, like the best travel times, weather, and costs.\n\n- **Three Key Agents:**\n - **City Selection Agent:** Picks the best places to visit based on your likes and current data.\n - **Local Expert Agent:** Gathers interesting details about what to do and see in the chosen city.\n - **Travel Concierge Agent:** Builds a day-by-day plan that includes where to stay, eat, and explore!\n\n- **Tools and Data:** Each agent uses tools to find and organize the latest information so you get recommendations that are both accurate and exciting.\n\n- **Final Plan:** Once everything is put together, you receive a complete, easy-to-follow travel itinerary, perfect for your adventure!\n", "display_name": "", @@ -806,7 +811,7 @@ }, "dragging": false, "height": 603, - "id": "note-CQDFw", + "id": "note-RAam9", "measured": { "height": 603, "width": 324 @@ -830,7 +835,7 @@ }, { "data": { - "id": "note-tuc3p", + "id": "note-tG6rx", "node": { "description": "# **City Selection Agent**\n - **Purpose:** This agent evaluates potential travel destinations based on user input and external data sources.\n - **Core Functions:** Analyzes factors such as weather, local events, and travel costs to recommend optimal cities.\n - **Tools Utilized:** Employs APIs and data-fetching tools to gather real-time information for decision-making.\n", "display_name": "", @@ -843,7 +848,7 @@ }, "dragging": false, "height": 334, - "id": "note-tuc3p", + "id": "note-tG6rx", "measured": { "height": 334, "width": 324 @@ -867,7 +872,7 @@ }, { "data": { - "id": "note-68RyJ", + "id": "note-j2Sf7", "node": { "description": "# **Local Expert Agent**\n - **Purpose:** Focused on gathering and providing an in-depth guide to the selected city.\n - **Core Functions:** Compiles insights into cultural attractions, local customs, and unique experiences.\n - **Tools Utilized:** Uses web content fetchers and data APIs to collect detailed local insights and enhance the user understanding with hidden gems.\n", "display_name": "", @@ -880,7 +885,7 @@ }, "dragging": false, "height": 342, - "id": "note-68RyJ", + "id": "note-j2Sf7", "measured": { "height": 342, "width": 324 @@ -904,7 +909,7 @@ }, { "data": { - "id": "note-2s03A", + "id": "note-0VHF3", "node": { "description": "# **Travel Concierge Agent**\n - **Purpose:** Crafts detailed travel itineraries that are customized to the traveler's interests and needs.\n - **Core Functions:** Offers a comprehensive daily schedule, including accommodations, dining spots, and activities.\n - **Tools Utilized:** Integrates calculators and data tools for accurate budget planning and itinerary logistics.", "display_name": "", @@ -917,7 +922,7 @@ }, "dragging": false, "height": 336, - "id": "note-2s03A", + "id": "note-0VHF3", "measured": { "height": 336, "width": 324 @@ -941,7 +946,7 @@ }, { "data": { - "id": "note-Qrd85", + "id": "note-OYU7j", "node": { "description": "## Configure the agent by obtaining your OpenAI API key from [platform.openai.com](https://platform.openai.com). Under \"Model Provider\", choose:\n- OpenAI: Default, requires only API key\n- Anthropic/Azure/Groq/NVIDIA: Each requires their own API keys\n- Custom: Use your own model endpoint + authentication\n\nSelect model and input API key before running the flow.", "display_name": "", @@ -954,7 +959,7 @@ }, "dragging": false, "height": 324, - "id": "note-Qrd85", + "id": "note-OYU7j", "measured": { "height": 324, "width": 324 @@ -974,2556 +979,16 @@ }, { "data": { - "id": "Agent-SVMdS", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "mode", - "message", - "memory", - "sender_type", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "options": null, - "required_inputs": null, - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "list_add_label": "Add More", - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Amazon Bedrock", - "Anthropic", - "Azure OpenAI", - "Google Generative AI", - "Groq", - "NVIDIA", - "OpenAI", - "SambaNova", - "Custom" - ], - "options_metadata": [ - { - "icon": "Anthropic" - }, - { - "icon": "GoogleGenerativeAI" - }, - { - "icon": "Groq" - }, - { - "icon": "OpenAI" - }, - { - "icon": "brain" - } - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "real_time_refresh": true, - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "list_add_label": "Add More", - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "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": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "list_add_label": "Add More", - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "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": true, - "display_name": "Mode", - "dynamic": false, - "info": "Operation mode: Store messages or Retrieve messages.", - "load_from_db": false, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "load_from_db": false, - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": false, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1" - }, - "n_messages": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Number of Messages", - "dynamic": false, - "info": "Number of messages to retrieve.", - "list": false, - "list_add_label": "Add More", - "name": "n_messages", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "sender": { - "_input_type": "MessageTextInput", - "advanced": true, - "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.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "Machine and User" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": false, - "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, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "copy_field": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a helpful assistant that can use tools to answer questions and perform tasks." - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "list_add_label": "Add More", - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "showNode": true, - "type": "Agent" - }, - "dragging": false, - "id": "Agent-SVMdS", - "measured": { - "height": 591, - "width": 320 - }, - "position": { - "x": 2462.5131863965653, - "y": 338.2948031203553 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Agent-Huf0O", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "mode", - "message", - "memory", - "sender_type", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "options": null, - "required_inputs": null, - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "list_add_label": "Add More", - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Amazon Bedrock", - "Anthropic", - "Azure OpenAI", - "Google Generative AI", - "Groq", - "NVIDIA", - "OpenAI", - "SambaNova", - "Custom" - ], - "options_metadata": [ - { - "icon": "Anthropic" - }, - { - "icon": "GoogleGenerativeAI" - }, - { - "icon": "Groq" - }, - { - "icon": "OpenAI" - }, - { - "icon": "brain" - } - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "real_time_refresh": true, - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "list_add_label": "Add More", - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "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": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "list_add_label": "Add More", - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "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": true, - "display_name": "Mode", - "dynamic": false, - "info": "Operation mode: Store messages or Retrieve messages.", - "load_from_db": false, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "load_from_db": false, - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": false, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1" - }, - "n_messages": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Number of Messages", - "dynamic": false, - "info": "Number of messages to retrieve.", - "list": false, - "list_add_label": "Add More", - "name": "n_messages", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "sender": { - "_input_type": "MessageTextInput", - "advanced": true, - "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.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "Machine and User" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": false, - "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, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "copy_field": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are a knowledgeable Local Expert with extensive information about the selected city, its attractions, and customs. Your goal is to provide the BEST insights about the city. Compile an in-depth guide for travelers, including key attractions, local customs, special events, and daily activity recommendations. Focus on hidden gems and local hotspots. Your final output should be a comprehensive city guide, rich in cultural insights and practical tips." - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "list_add_label": "Add More", - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "showNode": true, - "type": "Agent" - }, - "dragging": false, - "id": "Agent-Huf0O", - "measured": { - "height": 591, - "width": 320 - }, - "position": { - "x": 3168.5639981397626, - "y": 342.7862450828752 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Agent-jiGgJ", - "node": { - "base_classes": [ - "Message" - ], - "beta": false, - "conditional_paths": [], - "custom_fields": {}, - "description": "Define the agent's instructions, then enter a task to complete using tools.", - "display_name": "Agent", - "documentation": "", - "edited": false, - "field_order": [ - "agent_llm", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed", - "max_retries", - "timeout", - "system_prompt", - "tools", - "input_value", - "handle_parsing_errors", - "verbose", - "max_iterations", - "agent_description", - "mode", - "message", - "memory", - "sender_type", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", - "add_current_date_tool" - ], - "frozen": false, - "icon": "bot", - "legacy": false, - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Response", - "group_outputs": false, - "method": "message_response", - "name": "response", - "options": null, - "required_inputs": null, - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "template": { - "_type": "Component", - "add_current_date_tool": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Current Date", - "dynamic": false, - "info": "If true, will add a tool to the agent that returns the current date.", - "list": false, - "list_add_label": "Add More", - "name": "add_current_date_tool", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "agent_description": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "display_name": "Agent Description [Deprecated]", - "dynamic": false, - "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "agent_description", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "A helpful assistant with access to the following tools:" - }, - "agent_llm": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Model Provider", - "dynamic": false, - "info": "The provider of the language model that the agent will use to generate responses.", - "input_types": [], - "name": "agent_llm", - "options": [ - "Amazon Bedrock", - "Anthropic", - "Azure OpenAI", - "Google Generative AI", - "Groq", - "NVIDIA", - "OpenAI", - "SambaNova", - "Custom" - ], - "options_metadata": [ - { - "icon": "Anthropic" - }, - { - "icon": "GoogleGenerativeAI" - }, - { - "icon": "Groq" - }, - { - "icon": "OpenAI" - }, - { - "icon": "brain" - } - ], - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "OpenAI" - }, - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "real_time_refresh": true, - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" - }, - "handle_parsing_errors": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Handle Parse Errors", - "dynamic": false, - "info": "Should the Agent fix errors when reading user input for better processing?", - "list": false, - "list_add_label": "Add More", - "name": "handle_parsing_errors", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - }, - "input_value": { - "_input_type": "MessageTextInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "The input provided by the user for the agent to process.", - "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": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_iterations": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Iterations", - "dynamic": false, - "info": "The maximum number of attempts the agent can make to complete its task before it stops.", - "list": false, - "list_add_label": "Add More", - "name": "max_iterations", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 15 - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "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": true, - "display_name": "Mode", - "dynamic": false, - "info": "Operation mode: Store messages or Retrieve messages.", - "load_from_db": false, - "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": "Store" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", - "load_from_db": false, - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "real_time_refresh": false, - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1" - }, - "n_messages": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Number of Messages", - "dynamic": false, - "info": "Number of messages to retrieve.", - "list": false, - "list_add_label": "Add More", - "name": "n_messages", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "sender": { - "_input_type": "MessageTextInput", - "advanced": true, - "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.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "Machine and User" - }, - "sender_name": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Sender Name", - "dynamic": false, - "info": "Filter by sender name.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "sender_name", - "placeholder": "", - "required": false, - "show": false, - "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, - "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": "" - }, - "system_prompt": { - "_input_type": "MultilineInput", - "advanced": false, - "copy_field": false, - "display_name": "Agent Instructions", - "dynamic": false, - "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_prompt", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "You are an Amazing Travel Concierge, a specialist in travel planning and logistics with decades of experience. Your goal is to create the most amazing travel itineraries with budget and packing suggestions for the city. Expand the city guide into a full 7-day travel itinerary with detailed per-day plans. Include weather forecasts, places to eat, packing suggestions, and a budget breakdown. Suggest actual places to visit, hotels to stay, and restaurants to go to. Your final output should be a complete expanded travel plan, formatted as markdown, encompassing a daily schedule, anticipated weather conditions, recommended clothing and items to pack, and a detailed budget." - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": true, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 1, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "template": { - "_input_type": "MultilineInput", - "advanced": true, - "copy_field": false, - "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, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "template", - "placeholder": "", - "required": false, - "show": false, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "{sender_name}: {text}" - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - }, - "tools": { - "_input_type": "HandleInput", - "advanced": false, - "display_name": "Tools", - "dynamic": false, - "info": "These are the tools that the agent can use to help with tasks.", - "input_types": [ - "Tool" - ], - "list": true, - "list_add_label": "Add More", - "name": "tools", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "verbose": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Verbose", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "verbose", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": true - } - }, - "tool_mode": false - }, - "selected_output": "response", - "showNode": true, - "type": "Agent" - }, - "dragging": false, - "id": "Agent-jiGgJ", - "measured": { - "height": 591, - "width": 320 - }, - "position": { - "x": 3936.123532016018, - "y": 356.3534774464019 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "SearchComponent-3nVDj", - "node": { - "base_classes": [ - "DataFrame" - ], - "beta": false, - "category": "search", - "conditional_paths": [], - "custom_fields": {}, - "description": "Call the searchapi.io API with result limiting", - "display_name": "Search API", - "documentation": "https://www.searchapi.io/docs/google", - "edited": false, - "field_order": [ - "engine", - "api_key", - "input_value", - "search_params", - "max_results", - "max_snippet_length" - ], - "frozen": false, - "icon": "SearchAPI", - "key": "SearchComponent", - "legacy": false, - "metadata": {}, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Toolset", - "group_outputs": false, - "hidden": null, - "method": "to_toolkit", - "name": "component_as_tool", - "options": null, - "required_inputs": null, - "selected": "Tool", - "tool_mode": true, - "types": [ - "Tool" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 4.574062563799057e-12, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "SearchAPI API Key", - "dynamic": false, - "info": "", - "input_types": [], - "load_from_db": false, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Any\n\nfrom langchain_community.utilities.searchapi import SearchApiAPIWrapper\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import DictInput, DropdownInput, IntInput, MultilineInput, SecretStrInput\nfrom langflow.io import Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass SearchComponent(Component):\n display_name: str = \"Search API\"\n description: str = \"Call the searchapi.io API with result limiting\"\n documentation: str = \"https://www.searchapi.io/docs/google\"\n icon = \"SearchAPI\"\n\n inputs = [\n DropdownInput(name=\"engine\", display_name=\"Engine\", value=\"google\", options=[\"google\", \"bing\", \"duckduckgo\"]),\n SecretStrInput(name=\"api_key\", display_name=\"SearchAPI API Key\", required=True),\n MultilineInput(\n name=\"input_value\",\n display_name=\"Input\",\n tool_mode=True,\n ),\n DictInput(name=\"search_params\", display_name=\"Search parameters\", advanced=True, is_list=True),\n IntInput(name=\"max_results\", display_name=\"Max Results\", value=5, advanced=True),\n IntInput(name=\"max_snippet_length\", display_name=\"Max Snippet Length\", value=100, advanced=True),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def _build_wrapper(self):\n return SearchApiAPIWrapper(engine=self.engine, searchapi_api_key=self.api_key)\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def fetch_content(self) -> list[Data]:\n wrapper = self._build_wrapper()\n\n def search_func(\n query: str, params: dict[str, Any] | None = None, max_results: int = 5, max_snippet_length: int = 100\n ) -> list[Data]:\n params = params or {}\n full_results = wrapper.results(query=query, **params)\n organic_results = full_results.get(\"organic_results\", [])[:max_results]\n\n return [\n Data(\n text=result.get(\"snippet\", \"\"),\n data={\n \"title\": result.get(\"title\", \"\")[:max_snippet_length],\n \"link\": result.get(\"link\", \"\"),\n \"snippet\": result.get(\"snippet\", \"\")[:max_snippet_length],\n },\n )\n for result in organic_results\n ]\n\n results = search_func(\n self.input_value,\n self.search_params or {},\n self.max_results,\n self.max_snippet_length,\n )\n self.status = results\n return results\n\n def fetch_content_dataframe(self) -> DataFrame:\n \"\"\"Convert the search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.fetch_content()\n return DataFrame(data)\n" - }, - "engine": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Engine", - "dynamic": false, - "info": "", - "name": "engine", - "options": [ - "google", - "bing", - "duckduckgo" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "toggle": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "google" - }, - "input_value": { - "_input_type": "MultilineInput", - "advanced": false, - "copy_field": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "max_results": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Results", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "max_results", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_snippet_length": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Snippet Length", - "dynamic": false, - "info": "", - "list": false, - "list_add_label": "Add More", - "name": "max_snippet_length", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 100 - }, - "search_params": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Search parameters", - "dynamic": false, - "info": "", - "list": true, - "list_add_label": "Add More", - "name": "search_params", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "tools_metadata": { - "_input_type": "ToolsInput", - "advanced": false, - "display_name": "Actions", - "dynamic": false, - "info": "Modify tool names and descriptions to help agents understand when to use each tool.", - "is_list": true, - "list_add_label": "Add More", - "name": "tools_metadata", - "placeholder": "", - "real_time_refresh": true, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "tools", - "value": [ - { - "args": { - "input_value": { - "default": "", - "description": "", - "title": "Input Value", - "type": "string" - } - }, - "description": "Call the searchapi.io API with result limiting", - "display_description": "Call the searchapi.io API with result limiting", - "display_name": "fetch_content_dataframe", - "name": "fetch_content_dataframe", - "readonly": false, - "status": true, - "tags": [ - "fetch_content_dataframe" - ] - } - ] - } - }, - "tool_mode": true - }, - "showNode": true, - "type": "SearchComponent" - }, - "dragging": false, - "id": "SearchComponent-3nVDj", - "measured": { - "height": 365, - "width": 320 - }, - "position": { - "x": 2093.1263360559856, - "y": 887.965322905591 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "URLComponent-8bgTS", + "description": "Load and retrieve data from specified URLs. Supports output in plain text, raw HTML, or JSON, with options for cleaning and separating multiple outputs.", + "display_name": "URL", + "id": "URL-sFiMQ", "node": { "base_classes": [ + "Data", "DataFrame", "Message" ], "beta": false, - "category": "data", "conditional_paths": [], "custom_fields": {}, "description": "Fetch content from one or more web pages, following links recursively.", @@ -3532,21 +997,14 @@ "edited": false, "field_order": [ "urls", - "max_depth", - "prevent_outside", - "use_async", "format", - "timeout", - "headers", - "filter_text_html", - "continue_on_failure", - "check_response_status", - "autoset_encoding" + "separator", + "clean_extra_whitespace" ], "frozen": false, "icon": "layout-template", - "key": "URLComponent", "legacy": false, + "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -3556,7 +1014,7 @@ "cache": true, "display_name": "Toolset", "group_outputs": false, - "hidden": null, + "hidden": false, "method": "to_toolkit", "name": "component_as_tool", "options": null, @@ -3570,7 +1028,6 @@ } ], "pinned": false, - "score": 2.220446049250313e-16, "template": { "_type": "Component", "autoset_encoding": { @@ -3625,7 +1082,7 @@ "show": true, "title_case": false, "type": "code", - "value": "import re\n\nimport requests\nfrom bs4 import BeautifulSoup\nfrom langchain_community.document_loaders import RecursiveUrlLoader\nfrom loguru import logger\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.helpers.data import safe_convert\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MessageTextInput, Output, SliderInput, TableInput\nfrom langflow.schema.dataframe import DataFrame\nfrom langflow.schema.message import Message\nfrom langflow.services.deps import get_settings_service\n\n# Constants\nDEFAULT_TIMEOUT = 30\nDEFAULT_MAX_DEPTH = 1\nDEFAULT_FORMAT = \"Text\"\nURL_REGEX = re.compile(\n r\"^(https?:\\/\\/)?\"\n r\"(www\\.)?\"\n r\"([a-zA-Z0-9.-]+)\"\n r\"(\\.[a-zA-Z]{2,})?\"\n r\"(:\\d+)?\"\n r\"(\\/[^\\s]*)?$\",\n re.IGNORECASE,\n)\n\n\nclass URLComponent(Component):\n \"\"\"A component that loads and parses content from web pages recursively.\n\n This component allows fetching content from one or more URLs, with options to:\n - Control crawl depth\n - Prevent crawling outside the root domain\n - Use async loading for better performance\n - Extract either raw HTML or clean text\n - Configure request headers and timeouts\n \"\"\"\n\n display_name = \"URL\"\n description = \"Fetch content from one or more web pages, following links recursively.\"\n icon = \"layout-template\"\n name = \"URLComponent\"\n\n inputs = [\n MessageTextInput(\n name=\"urls\",\n display_name=\"URLs\",\n info=\"Enter one or more URLs to crawl recursively, by clicking the '+' button.\",\n is_list=True,\n tool_mode=True,\n placeholder=\"Enter a URL...\",\n list_add_label=\"Add URL\",\n input_types=[],\n ),\n SliderInput(\n name=\"max_depth\",\n display_name=\"Depth\",\n info=(\n \"Controls how many 'clicks' away from the initial page the crawler will go:\\n\"\n \"- depth 1: only the initial page\\n\"\n \"- depth 2: initial page + all pages linked directly from it\\n\"\n \"- depth 3: initial page + direct links + links found on those direct link pages\\n\"\n \"Note: This is about link traversal, not URL path depth.\"\n ),\n value=DEFAULT_MAX_DEPTH,\n range_spec=RangeSpec(min=1, max=5, step=1),\n required=False,\n min_label=\" \",\n max_label=\" \",\n min_label_icon=\"None\",\n max_label_icon=\"None\",\n # slider_input=True\n ),\n BoolInput(\n name=\"prevent_outside\",\n display_name=\"Prevent Outside\",\n info=(\n \"If enabled, only crawls URLs within the same domain as the root URL. \"\n \"This helps prevent the crawler from going to external websites.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"use_async\",\n display_name=\"Use Async\",\n info=(\n \"If enabled, uses asynchronous loading which can be significantly faster \"\n \"but might use more system resources.\"\n ),\n value=True,\n required=False,\n advanced=True,\n ),\n DropdownInput(\n name=\"format\",\n display_name=\"Output Format\",\n info=\"Output Format. Use 'Text' to extract the text from the HTML or 'HTML' for the raw HTML content.\",\n options=[\"Text\", \"HTML\"],\n value=DEFAULT_FORMAT,\n advanced=True,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"Timeout for the request in seconds.\",\n value=DEFAULT_TIMEOUT,\n required=False,\n advanced=True,\n ),\n TableInput(\n name=\"headers\",\n display_name=\"Headers\",\n info=\"The headers to send with the request\",\n table_schema=[\n {\n \"name\": \"key\",\n \"display_name\": \"Header\",\n \"type\": \"str\",\n \"description\": \"Header name\",\n },\n {\n \"name\": \"value\",\n \"display_name\": \"Value\",\n \"type\": \"str\",\n \"description\": \"Header value\",\n },\n ],\n value=[{\"key\": \"User-Agent\", \"value\": get_settings_service().settings.user_agent}],\n advanced=True,\n input_types=[\"DataFrame\"],\n ),\n BoolInput(\n name=\"filter_text_html\",\n display_name=\"Filter Text/HTML\",\n info=\"If enabled, filters out text/css content type from the results.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"continue_on_failure\",\n display_name=\"Continue on Failure\",\n info=\"If enabled, continues crawling even if some requests fail.\",\n value=True,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"check_response_status\",\n display_name=\"Check Response Status\",\n info=\"If enabled, checks the response status of the request.\",\n value=False,\n required=False,\n advanced=True,\n ),\n BoolInput(\n name=\"autoset_encoding\",\n display_name=\"Autoset Encoding\",\n info=\"If enabled, automatically sets the encoding of the request.\",\n value=True,\n required=False,\n advanced=True,\n ),\n ]\n\n outputs = [\n Output(display_name=\"Extracted Pages\", name=\"page_results\", method=\"fetch_content\"),\n Output(display_name=\"Raw Content\", name=\"raw_results\", method=\"fetch_content_as_message\", tool_mode=False),\n ]\n\n @staticmethod\n def validate_url(url: str) -> bool:\n \"\"\"Validates if the given string matches URL pattern.\n\n Args:\n url: The URL string to validate\n\n Returns:\n bool: True if the URL is valid, False otherwise\n \"\"\"\n return bool(URL_REGEX.match(url))\n\n def ensure_url(self, url: str) -> str:\n \"\"\"Ensures the given string is a valid URL.\n\n Args:\n url: The URL string to validate and normalize\n\n Returns:\n str: The normalized URL\n\n Raises:\n ValueError: If the URL is invalid\n \"\"\"\n url = url.strip()\n if not url.startswith((\"http://\", \"https://\")):\n url = \"https://\" + url\n\n if not self.validate_url(url):\n msg = f\"Invalid URL: {url}\"\n raise ValueError(msg)\n\n return url\n\n def _create_loader(self, url: str) -> RecursiveUrlLoader:\n \"\"\"Creates a RecursiveUrlLoader instance with the configured settings.\n\n Args:\n url: The URL to load\n\n Returns:\n RecursiveUrlLoader: Configured loader instance\n \"\"\"\n headers_dict = {header[\"key\"]: header[\"value\"] for header in self.headers}\n extractor = (lambda x: x) if self.format == \"HTML\" else (lambda x: BeautifulSoup(x, \"lxml\").get_text())\n\n return RecursiveUrlLoader(\n url=url,\n max_depth=self.max_depth,\n prevent_outside=self.prevent_outside,\n use_async=self.use_async,\n extractor=extractor,\n timeout=self.timeout,\n headers=headers_dict,\n check_response_status=self.check_response_status,\n continue_on_failure=self.continue_on_failure,\n base_url=url, # Add base_url to ensure consistent domain crawling\n autoset_encoding=self.autoset_encoding, # Enable automatic encoding detection\n exclude_dirs=[], # Allow customization of excluded directories\n link_regex=None, # Allow customization of link filtering\n )\n\n def fetch_url_contents(self) -> list[dict]:\n \"\"\"Load documents from the configured URLs.\n\n Returns:\n List[Data]: List of Data objects containing the fetched content\n\n Raises:\n ValueError: If no valid URLs are provided or if there's an error loading documents\n \"\"\"\n try:\n urls = list({self.ensure_url(url) for url in self.urls if url.strip()})\n logger.info(f\"URLs: {urls}\")\n if not urls:\n msg = \"No valid URLs provided.\"\n raise ValueError(msg)\n\n all_docs = []\n for url in urls:\n logger.info(f\"Loading documents from {url}\")\n\n try:\n loader = self._create_loader(url)\n docs = loader.load()\n\n if not docs:\n logger.warning(f\"No documents found for {url}\")\n continue\n\n logger.info(f\"Found {len(docs)} documents from {url}\")\n all_docs.extend(docs)\n\n except requests.exceptions.RequestException as e:\n logger.exception(f\"Error loading documents from {url}: {e}\")\n continue\n\n if not all_docs:\n msg = \"No documents were successfully loaded from any URL\"\n raise ValueError(msg)\n\n # data = [Data(text=doc.page_content, **doc.metadata) for doc in all_docs]\n data = [\n {\n \"text\": safe_convert(doc.page_content, clean_data=True),\n \"url\": doc.metadata.get(\"source\", \"\"),\n \"title\": doc.metadata.get(\"title\", \"\"),\n \"description\": doc.metadata.get(\"description\", \"\"),\n \"content_type\": doc.metadata.get(\"content_type\", \"\"),\n \"language\": doc.metadata.get(\"language\", \"\"),\n }\n for doc in all_docs\n ]\n except Exception as e:\n error_msg = e.message if hasattr(e, \"message\") else e\n msg = f\"Error loading documents: {error_msg!s}\"\n logger.exception(msg)\n raise ValueError(msg) from e\n return data\n\n def fetch_content(self) -> DataFrame:\n \"\"\"Convert the documents to a DataFrame.\"\"\"\n return DataFrame(data=self.fetch_url_contents())\n\n def fetch_content_as_message(self) -> Message:\n \"\"\"Convert the documents to a Message.\"\"\"\n url_contents = self.fetch_url_contents()\n return Message(text=\"\\n\\n\".join([x[\"text\"] for x in url_contents]), data={\"data\": url_contents})\n" + "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", @@ -3678,10 +1135,10 @@ ], "options_metadata": [], "placeholder": "", + "real_time_refresh": true, "required": false, "show": true, "title_case": false, - "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -3849,6 +1306,28 @@ "tags": [ "fetch_content" ] + }, + { + "args": { + "urls": { + "default": "", + "description": "Enter one or more URLs to crawl recursively, by clicking the '+' button.", + "items": { + "type": "string" + }, + "title": "Urls", + "type": "array" + } + }, + "description": "Fetch content from one or more web pages, following links recursively.", + "display_description": "Fetch content from one or more web pages, following links recursively.", + "display_name": "as_message", + "name": "as_message", + "readonly": false, + "status": true, + "tags": [ + "as_message" + ] } ] }, @@ -3894,31 +1373,32 @@ }, "tool_mode": true }, + "selected_output": "component_as_tool", "showNode": true, - "type": "URLComponent" + "type": "URL" }, "dragging": false, - "id": "URLComponent-8bgTS", + "id": "URL-sFiMQ", "measured": { - "height": 289, + "height": 290, "width": 320 }, "position": { - "x": 2713.896825977834, - "y": 998.9242993650518 + "x": 2815.5187953791974, + "y": 949.802524756467 }, "selected": false, "type": "genericNode" }, { "data": { - "id": "CalculatorComponent-JKeHR", + "id": "CalculatorComponent-oWut2", "node": { "base_classes": [ "Data" ], "beta": false, - "category": "helpers", + "category": "tools", "conditional_paths": [], "custom_fields": {}, "description": "Perform basic arithmetic operations on a given expression.", @@ -3932,6 +1412,7 @@ "icon": "calculator", "key": "CalculatorComponent", "legacy": false, + "lf_version": "1.2.0", "metadata": {}, "minimized": false, "output_types": [], @@ -3941,7 +1422,7 @@ "cache": true, "display_name": "Toolset", "group_outputs": false, - "hidden": null, + "hidden": false, "method": "to_toolkit", "name": "component_as_tool", "options": null, @@ -4026,11 +1507,10 @@ "type": "string" } }, - "description": "Perform basic arithmetic operations on a given expression.", - "display_description": "Perform basic arithmetic operations on a given expression.", + "description": "CalculatorComponent. evaluate_expression() - Perform basic arithmetic operations on a given expression.", + "display_description": "CalculatorComponent. evaluate_expression() - Perform basic arithmetic operations on a given expression.", "display_name": "evaluate_expression", "name": "evaluate_expression", - "readonly": false, "status": true, "tags": [ "evaluate_expression" @@ -4041,32 +1521,1917 @@ }, "tool_mode": true }, + "selected_output": "component_as_tool", "showNode": true, "type": "CalculatorComponent" }, "dragging": false, - "id": "CalculatorComponent-JKeHR", + "id": "CalculatorComponent-oWut2", "measured": { - "height": 217, + "height": 218, "width": 320 }, "position": { - "x": 3427.6329448251768, - "y": 1066.3993526174263 + "x": 3540.356346381247, + "y": 989.3563951826354 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "description": "Call the searchapi.io API with result limiting", + "display_name": "Search API", + "id": "SearchComponent-vbaqY", + "node": { + "base_classes": [ + "Data", + "DataFrame", + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Call the searchapi.io API with result limiting", + "display_name": "Search API", + "documentation": "https://www.searchapi.io/docs/google", + "edited": false, + "field_order": [ + "engine", + "api_key", + "input_value", + "search_params", + "max_results", + "max_snippet_length" + ], + "frozen": false, + "icon": "SearchAPI", + "legacy": false, + "lf_version": "1.2.0", + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Toolset", + "group_outputs": false, + "hidden": null, + "method": "to_toolkit", + "name": "component_as_tool", + "options": null, + "required_inputs": null, + "selected": "Tool", + "tool_mode": true, + "types": [ + "Tool" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "SearchAPI API Key", + "dynamic": false, + "info": "", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_community.utilities.searchapi import SearchApiAPIWrapper\n\nfrom langflow.custom.custom_component.component import Component\nfrom langflow.inputs.inputs import DictInput, DropdownInput, IntInput, MultilineInput, SecretStrInput\nfrom langflow.io import Output\nfrom langflow.schema.data import Data\nfrom langflow.schema.dataframe import DataFrame\n\n\nclass SearchComponent(Component):\n display_name: str = \"Search API\"\n description: str = \"Call the searchapi.io API with result limiting\"\n documentation: str = \"https://www.searchapi.io/docs/google\"\n icon = \"SearchAPI\"\n\n inputs = [\n DropdownInput(name=\"engine\", display_name=\"Engine\", value=\"google\", options=[\"google\", \"bing\", \"duckduckgo\"]),\n SecretStrInput(name=\"api_key\", display_name=\"SearchAPI API Key\", required=True),\n MultilineInput(\n name=\"input_value\",\n display_name=\"Input\",\n tool_mode=True,\n ),\n DictInput(name=\"search_params\", display_name=\"Search parameters\", advanced=True, is_list=True),\n IntInput(name=\"max_results\", display_name=\"Max Results\", value=5, advanced=True),\n IntInput(name=\"max_snippet_length\", display_name=\"Max Snippet Length\", value=100, advanced=True),\n ]\n\n outputs = [\n Output(display_name=\"DataFrame\", name=\"dataframe\", method=\"fetch_content_dataframe\"),\n ]\n\n def _build_wrapper(self):\n return SearchApiAPIWrapper(engine=self.engine, searchapi_api_key=self.api_key)\n\n def run_model(self) -> DataFrame:\n return self.fetch_content_dataframe()\n\n def fetch_content(self) -> list[Data]:\n wrapper = self._build_wrapper()\n\n def search_func(\n query: str, params: dict[str, Any] | None = None, max_results: int = 5, max_snippet_length: int = 100\n ) -> list[Data]:\n params = params or {}\n full_results = wrapper.results(query=query, **params)\n organic_results = full_results.get(\"organic_results\", [])[:max_results]\n\n return [\n Data(\n text=result.get(\"snippet\", \"\"),\n data={\n \"title\": result.get(\"title\", \"\")[:max_snippet_length],\n \"link\": result.get(\"link\", \"\"),\n \"snippet\": result.get(\"snippet\", \"\")[:max_snippet_length],\n },\n )\n for result in organic_results\n ]\n\n results = search_func(\n self.input_value,\n self.search_params or {},\n self.max_results,\n self.max_snippet_length,\n )\n self.status = results\n return results\n\n def fetch_content_dataframe(self) -> DataFrame:\n \"\"\"Convert the search results to a DataFrame.\n\n Returns:\n DataFrame: A DataFrame containing the search results.\n \"\"\"\n data = self.fetch_content()\n return DataFrame(data)\n" + }, + "engine": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Engine", + "dynamic": false, + "info": "", + "name": "engine", + "options": [ + "google", + "bing", + "duckduckgo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "google" + }, + "input_value": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Input", + "dynamic": false, + "info": "", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "max_results": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Results", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "max_results", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_snippet_length": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Snippet Length", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "max_snippet_length", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "search_params": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Search parameters", + "dynamic": false, + "info": "", + "list": true, + "list_add_label": "Add More", + "name": "search_params", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "tools_metadata": { + "_input_type": "ToolsInput", + "advanced": false, + "display_name": "Actions", + "dynamic": false, + "info": "Modify tool names and descriptions to help agents understand when to use each tool.", + "is_list": true, + "list_add_label": "Add More", + "name": "tools_metadata", + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "tools", + "value": [ + { + "args": { + "input_value": { + "default": "", + "description": "", + "title": "Input Value", + "type": "string" + } + }, + "description": "Call the searchapi.io API with result limiting", + "display_description": "Call the searchapi.io API with result limiting", + "display_name": "fetch_content_dataframe", + "name": "fetch_content_dataframe", + "readonly": false, + "status": true, + "tags": [ + "fetch_content_dataframe" + ] + } + ] + } + }, + "tool_mode": true + }, + "selected_output": "component_as_tool", + "showNode": true, + "type": "SearchComponent" + }, + "dragging": false, + "id": "SearchComponent-vbaqY", + "measured": { + "height": 367, + "width": 320 + }, + "position": { + "x": 2089.0393126914205, + "y": 894.9349094163676 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "Agent-c2dqD", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "City Selection Agent", + "documentation": "", + "edited": false, + "field_order": [ + "agent_llm", + "max_tokens", + "model_kwargs", + "json_mode", + "model_name", + "openai_api_base", + "api_key", + "temperature", + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" + ], + "frozen": false, + "icon": "bot", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Response", + "group_outputs": false, + "hidden": null, + "method": "message_response", + "name": "response", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": true, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "input_value": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input provided by the user for the agent to process.", + "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": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "json_mode": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "JSON Mode", + "dynamic": false, + "info": "If True, it will output JSON regardless of passing a schema.", + "list": false, + "list_add_label": "Add More", + "name": "json_mode", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, + "max_retries": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "The maximum number of retries to make when generating.", + "list": false, + "list_add_label": "Add More", + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_tokens": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "list_add_label": "Add More", + "name": "max_tokens", + "placeholder": "", + "range_spec": { + "max": 128000, + "min": 0, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "Additional keyword arguments to pass to the model.", + "list": false, + "list_add_label": "Add More", + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": true, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo", + "o1" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4.1" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "openai_api_base": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "seed": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "list_add_label": "Add More", + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "system_prompt": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Agent Instructions", + "dynamic": false, + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_prompt", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "You are a helpful assistant that can use tools to answer questions and perform tasks." + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "The timeout for requests to OpenAI completion API.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + } + }, + "tool_mode": false + }, + "selected_output": "response", + "showNode": true, + "type": "Agent" + }, + "dragging": false, + "id": "Agent-c2dqD", + "measured": { + "height": 594, + "width": 320 + }, + "position": { + "x": 2462.5131863965653, + "y": 338.2948031203553 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "Agent-kfSsu", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "Local Expert Agent", + "documentation": "", + "edited": false, + "field_order": [ + "agent_llm", + "max_tokens", + "model_kwargs", + "json_mode", + "model_name", + "openai_api_base", + "api_key", + "temperature", + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" + ], + "frozen": false, + "icon": "bot", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Response", + "group_outputs": false, + "hidden": null, + "method": "message_response", + "name": "response", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": true, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "input_value": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input provided by the user for the agent to process.", + "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": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "json_mode": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "JSON Mode", + "dynamic": false, + "info": "If True, it will output JSON regardless of passing a schema.", + "list": false, + "list_add_label": "Add More", + "name": "json_mode", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, + "max_retries": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "The maximum number of retries to make when generating.", + "list": false, + "list_add_label": "Add More", + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_tokens": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "list_add_label": "Add More", + "name": "max_tokens", + "placeholder": "", + "range_spec": { + "max": 128000, + "min": 0, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "Additional keyword arguments to pass to the model.", + "list": false, + "list_add_label": "Add More", + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": true, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo", + "o1" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4.1" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "openai_api_base": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "seed": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "list_add_label": "Add More", + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "system_prompt": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Agent Instructions", + "dynamic": false, + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_prompt", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "You are a knowledgeable Local Expert with extensive information about the selected city, its attractions, and customs. Your goal is to provide the BEST insights about the city. Compile an in-depth guide for travelers, including key attractions, local customs, special events, and daily activity recommendations. Focus on hidden gems and local hotspots. Your final output should be a comprehensive city guide, rich in cultural insights and practical tips." + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "The timeout for requests to OpenAI completion API.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + } + }, + "tool_mode": false + }, + "selected_output": "response", + "showNode": true, + "type": "Agent" + }, + "dragging": false, + "id": "Agent-kfSsu", + "measured": { + "height": 594, + "width": 320 + }, + "position": { + "x": 3168.5639981397626, + "y": 342.7862450828752 + }, + "selected": false, + "type": "genericNode" + }, + { + "data": { + "id": "Agent-fMEDP", + "node": { + "base_classes": [ + "Message" + ], + "beta": false, + "conditional_paths": [], + "custom_fields": {}, + "description": "Define the agent's instructions, then enter a task to complete using tools.", + "display_name": "Travel Concierge Agent", + "documentation": "", + "edited": false, + "field_order": [ + "agent_llm", + "max_tokens", + "model_kwargs", + "json_mode", + "model_name", + "openai_api_base", + "api_key", + "temperature", + "seed", + "max_retries", + "timeout", + "system_prompt", + "n_messages", + "tools", + "input_value", + "handle_parsing_errors", + "verbose", + "max_iterations", + "agent_description", + "add_current_date_tool" + ], + "frozen": false, + "icon": "bot", + "legacy": false, + "metadata": {}, + "minimized": false, + "output_types": [], + "outputs": [ + { + "allows_loop": false, + "cache": true, + "display_name": "Response", + "group_outputs": false, + "hidden": null, + "method": "message_response", + "name": "response", + "options": null, + "required_inputs": null, + "selected": "Message", + "tool_mode": true, + "types": [ + "Message" + ], + "value": "__UNDEFINED__" + } + ], + "pinned": false, + "template": { + "_type": "Component", + "add_current_date_tool": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Current Date", + "dynamic": false, + "info": "If true, will add a tool to the agent that returns the current date.", + "list": false, + "list_add_label": "Add More", + "name": "add_current_date_tool", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "agent_description": { + "_input_type": "MultilineInput", + "advanced": true, + "copy_field": false, + "display_name": "Agent Description [Deprecated]", + "dynamic": false, + "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "agent_description", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "A helpful assistant with access to the following tools:" + }, + "agent_llm": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "The provider of the language model that the agent will use to generate responses.", + "input_types": [], + "name": "agent_llm", + "options": [ + "Anthropic", + "Google Generative AI", + "Groq", + "OpenAI", + "Custom" + ], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "api_key": { + "_input_type": "SecretStrInput", + "advanced": false, + "display_name": "OpenAI API Key", + "dynamic": false, + "info": "The OpenAI API Key to use for the OpenAI model.", + "input_types": [], + "load_from_db": true, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": true, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + }, + "handle_parsing_errors": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Handle Parse Errors", + "dynamic": false, + "info": "Should the Agent fix errors when reading user input for better processing?", + "list": false, + "list_add_label": "Add More", + "name": "handle_parsing_errors", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + }, + "input_value": { + "_input_type": "MessageTextInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input provided by the user for the agent to process.", + "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": true, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "json_mode": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "JSON Mode", + "dynamic": false, + "info": "If True, it will output JSON regardless of passing a schema.", + "list": false, + "list_add_label": "Add More", + "name": "json_mode", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "max_iterations": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Iterations", + "dynamic": false, + "info": "The maximum number of attempts the agent can make to complete its task before it stops.", + "list": false, + "list_add_label": "Add More", + "name": "max_iterations", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 15 + }, + "max_retries": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Retries", + "dynamic": false, + "info": "The maximum number of retries to make when generating.", + "list": false, + "list_add_label": "Add More", + "name": "max_retries", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 5 + }, + "max_tokens": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Max Tokens", + "dynamic": false, + "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", + "list": false, + "list_add_label": "Add More", + "name": "max_tokens", + "placeholder": "", + "range_spec": { + "max": 128000, + "min": 0, + "step": 0.1, + "step_type": "float" + }, + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": "" + }, + "model_kwargs": { + "_input_type": "DictInput", + "advanced": true, + "display_name": "Model Kwargs", + "dynamic": false, + "info": "Additional keyword arguments to pass to the model.", + "list": false, + "list_add_label": "Add More", + "name": "model_kwargs", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "type": "dict", + "value": {} + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": true, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo", + "o1" + ], + "options_metadata": [], + "placeholder": "", + "real_time_refresh": false, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4.1" + }, + "n_messages": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Number of Chat History Messages", + "dynamic": false, + "info": "Number of chat history messages to retrieve.", + "list": false, + "list_add_label": "Add More", + "name": "n_messages", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 100 + }, + "openai_api_base": { + "_input_type": "StrInput", + "advanced": true, + "display_name": "OpenAI API Base", + "dynamic": false, + "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "openai_api_base", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "seed": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Seed", + "dynamic": false, + "info": "The seed controls the reproducibility of the job.", + "list": false, + "list_add_label": "Add More", + "name": "seed", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 1 + }, + "system_prompt": { + "_input_type": "MultilineInput", + "advanced": false, + "copy_field": false, + "display_name": "Agent Instructions", + "dynamic": false, + "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "multiline": true, + "name": "system_prompt", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "You are an Amazing Travel Concierge, a specialist in travel planning and logistics with decades of experience. Your goal is to create the most amazing travel itineraries with budget and packing suggestions for the city. Expand the city guide into a full 7-day travel itinerary with detailed per-day plans. Include weather forecasts, places to eat, packing suggestions, and a budget breakdown. Suggest actual places to visit, hotels to stay, and restaurants to go to. Your final output should be a complete expanded travel plan, formatted as markdown, encompassing a daily schedule, anticipated weather conditions, recommended clothing and items to pack, and a detailed budget." + }, + "temperature": { + "_input_type": "SliderInput", + "advanced": true, + "display_name": "Temperature", + "dynamic": false, + "info": "", + "max_label": "", + "max_label_icon": "", + "min_label": "", + "min_label_icon": "", + "name": "temperature", + "placeholder": "", + "range_spec": { + "max": 1, + "min": 0, + "step": 0.01, + "step_type": "float" + }, + "required": false, + "show": true, + "slider_buttons": false, + "slider_buttons_options": [], + "slider_input": false, + "title_case": false, + "tool_mode": false, + "type": "slider", + "value": 0.1 + }, + "timeout": { + "_input_type": "IntInput", + "advanced": true, + "display_name": "Timeout", + "dynamic": false, + "info": "The timeout for requests to OpenAI completion API.", + "list": false, + "list_add_label": "Add More", + "name": "timeout", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "int", + "value": 700 + }, + "tools": { + "_input_type": "HandleInput", + "advanced": false, + "display_name": "Tools", + "dynamic": false, + "info": "These are the tools that the agent can use to help with tasks.", + "input_types": [ + "Tool" + ], + "list": true, + "list_add_label": "Add More", + "name": "tools", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "trace_as_metadata": true, + "type": "other", + "value": "" + }, + "verbose": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Verbose", + "dynamic": false, + "info": "", + "list": false, + "list_add_label": "Add More", + "name": "verbose", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": true + } + }, + "tool_mode": false + }, + "selected_output": "response", + "showNode": true, + "type": "Agent" + }, + "dragging": false, + "id": "Agent-fMEDP", + "measured": { + "height": 594, + "width": 320 + }, + "position": { + "x": 3936.123532016018, + "y": 356.3534774464019 }, "selected": true, "type": "genericNode" } ], "viewport": { - "x": -1956.9334684808755, - "y": -270.19574649754327, - "zoom": 0.6669131453914963 + "x": -2326.466810721881, + "y": -65.11181133103509, + "zoom": 0.7857888154223331 } }, "description": "Create a travel planning chatbot that uses specialized agents to craft personalized trip itineraries.", "endpoint_name": null, - "id": "95d851e7-4eb4-445b-a506-224570a44f37", + "id": "fe4a9ae2-3097-4f93-8c2a-beb63009178b", "is_component": false, "last_tested_version": "1.4.3", "name": "Travel Planning Agents", diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json b/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json index af0415fa1..a29c61e9a 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json @@ -7,7 +7,7 @@ "data": { "sourceHandle": { "dataType": "YouTubeCommentsComponent", - "id": "YouTubeCommentsComponent-4pxuY", + "id": "YouTubeCommentsComponent-0EgiI", "name": "comments", "output_types": [ "DataFrame" @@ -15,47 +15,19 @@ }, "targetHandle": { "fieldName": "df", - "id": "BatchRunComponent-jFt7j", + "id": "BatchRunComponent-4Ou5s", "inputTypes": [ "DataFrame" ], "type": "other" } }, - "id": "reactflow__edge-YouTubeCommentsComponent-4pxuY{œdataTypeœ:œYouTubeCommentsComponentœ,œidœ:œYouTubeCommentsComponent-4pxuYœ,œnameœ:œcommentsœ,œoutput_typesœ:[œDataFrameœ]}-BatchRunComponent-jFt7j{œfieldNameœ:œdfœ,œidœ:œBatchRunComponent-jFt7jœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-YouTubeCommentsComponent-0EgiI{œdataTypeœ:œYouTubeCommentsComponentœ,œidœ:œYouTubeCommentsComponent-0EgiIœ,œnameœ:œcommentsœ,œoutput_typesœ:[œDataFrameœ]}-BatchRunComponent-4Ou5s{œfieldNameœ:œdfœ,œidœ:œBatchRunComponent-4Ou5sœ,œinputTypesœ:[œDataFrameœ],œtypeœ:œotherœ}", "selected": false, - "source": "YouTubeCommentsComponent-4pxuY", - "sourceHandle": "{œdataTypeœ: œYouTubeCommentsComponentœ, œidœ: œYouTubeCommentsComponent-4pxuYœ, œnameœ: œcommentsœ, œoutput_typesœ: [œDataFrameœ]}", - "target": "BatchRunComponent-jFt7j", - "targetHandle": "{œfieldNameœ: œdfœ, œidœ: œBatchRunComponent-jFt7jœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}" - }, - { - "animated": false, - "className": "", - "data": { - "sourceHandle": { - "dataType": "OpenAIModel", - "id": "OpenAIModel-3klNa", - "name": "model_output", - "output_types": [ - "LanguageModel" - ] - }, - "targetHandle": { - "fieldName": "model", - "id": "BatchRunComponent-jFt7j", - "inputTypes": [ - "LanguageModel" - ], - "type": "other" - } - }, - "id": "reactflow__edge-OpenAIModel-3klNa{œdataTypeœ:œOpenAIModelœ,œidœ:œOpenAIModel-3klNaœ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-BatchRunComponent-jFt7j{œfieldNameœ:œmodelœ,œidœ:œBatchRunComponent-jFt7jœ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}", - "selected": false, - "source": "OpenAIModel-3klNa", - "sourceHandle": "{œdataTypeœ: œOpenAIModelœ, œidœ: œOpenAIModel-3klNaœ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}", - "target": "BatchRunComponent-jFt7j", - "targetHandle": "{œfieldNameœ: œmodelœ, œidœ: œBatchRunComponent-jFt7jœ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}" + "source": "YouTubeCommentsComponent-0EgiI", + "sourceHandle": "{œdataTypeœ: œYouTubeCommentsComponentœ, œidœ: œYouTubeCommentsComponent-0EgiIœ, œnameœ: œcommentsœ, œoutput_typesœ: [œDataFrameœ]}", + "target": "BatchRunComponent-4Ou5s", + "targetHandle": "{œfieldNameœ: œdfœ, œidœ: œBatchRunComponent-4Ou5sœ, œinputTypesœ: [œDataFrameœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -63,7 +35,7 @@ "data": { "sourceHandle": { "dataType": "Prompt", - "id": "Prompt-tR2a7", + "id": "Prompt-uQBug", "name": "prompt", "output_types": [ "Message" @@ -71,19 +43,19 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "Agent-A37q9", + "id": "Agent-H93Cv", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-Prompt-tR2a7{œdataTypeœ:œPromptœ,œidœ:œPrompt-tR2a7œ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-A37q9{œfieldNameœ:œinput_valueœ,œidœ:œAgent-A37q9œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Prompt-uQBug{œdataTypeœ:œPromptœ,œidœ:œPrompt-uQBugœ,œnameœ:œpromptœ,œoutput_typesœ:[œMessageœ]}-Agent-H93Cv{œfieldNameœ:œinput_valueœ,œidœ:œAgent-H93Cvœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Prompt-tR2a7", - "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-tR2a7œ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", - "target": "Agent-A37q9", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-A37q9œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "Prompt-uQBug", + "sourceHandle": "{œdataTypeœ: œPromptœ, œidœ: œPrompt-uQBugœ, œnameœ: œpromptœ, œoutput_typesœ: [œMessageœ]}", + "target": "Agent-H93Cv", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œAgent-H93Cvœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -91,7 +63,7 @@ "data": { "sourceHandle": { "dataType": "Agent", - "id": "Agent-A37q9", + "id": "Agent-H93Cv", "name": "response", "output_types": [ "Message" @@ -99,7 +71,7 @@ }, "targetHandle": { "fieldName": "input_value", - "id": "ChatOutput-w4PAC", + "id": "ChatOutput-rRSvO", "inputTypes": [ "Data", "DataFrame", @@ -108,12 +80,12 @@ "type": "str" } }, - "id": "reactflow__edge-Agent-A37q9{œdataTypeœ:œAgentœ,œidœ:œAgent-A37q9œ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-w4PAC{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-w4PACœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-Agent-H93Cv{œdataTypeœ:œAgentœ,œidœ:œAgent-H93Cvœ,œnameœ:œresponseœ,œoutput_typesœ:[œMessageœ]}-ChatOutput-rRSvO{œfieldNameœ:œinput_valueœ,œidœ:œChatOutput-rRSvOœ,œinputTypesœ:[œDataœ,œDataFrameœ,œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "Agent-A37q9", - "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-A37q9œ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", - "target": "ChatOutput-w4PAC", - "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-w4PACœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" + "source": "Agent-H93Cv", + "sourceHandle": "{œdataTypeœ: œAgentœ, œidœ: œAgent-H93Cvœ, œnameœ: œresponseœ, œoutput_typesœ: [œMessageœ]}", + "target": "ChatOutput-rRSvO", + "targetHandle": "{œfieldNameœ: œinput_valueœ, œidœ: œChatOutput-rRSvOœ, œinputTypesœ: [œDataœ, œDataFrameœ, œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -121,7 +93,7 @@ "data": { "sourceHandle": { "dataType": "YouTubeTranscripts", - "id": "YouTubeTranscripts-Nbrx3", + "id": "YouTubeTranscripts-eg1lO", "name": "component_as_tool", "output_types": [ "Tool" @@ -129,19 +101,19 @@ }, "targetHandle": { "fieldName": "tools", - "id": "Agent-A37q9", + "id": "Agent-H93Cv", "inputTypes": [ "Tool" ], "type": "other" } }, - "id": "reactflow__edge-YouTubeTranscripts-Nbrx3{œdataTypeœ:œYouTubeTranscriptsœ,œidœ:œYouTubeTranscripts-Nbrx3œ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-A37q9{œfieldNameœ:œtoolsœ,œidœ:œAgent-A37q9œ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-YouTubeTranscripts-eg1lO{œdataTypeœ:œYouTubeTranscriptsœ,œidœ:œYouTubeTranscripts-eg1lOœ,œnameœ:œcomponent_as_toolœ,œoutput_typesœ:[œToolœ]}-Agent-H93Cv{œfieldNameœ:œtoolsœ,œidœ:œAgent-H93Cvœ,œinputTypesœ:[œToolœ],œtypeœ:œotherœ}", "selected": false, - "source": "YouTubeTranscripts-Nbrx3", - "sourceHandle": "{œdataTypeœ: œYouTubeTranscriptsœ, œidœ: œYouTubeTranscripts-Nbrx3œ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", - "target": "Agent-A37q9", - "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-A37q9œ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" + "source": "YouTubeTranscripts-eg1lO", + "sourceHandle": "{œdataTypeœ: œYouTubeTranscriptsœ, œidœ: œYouTubeTranscripts-eg1lOœ, œnameœ: œcomponent_as_toolœ, œoutput_typesœ: [œToolœ]}", + "target": "Agent-H93Cv", + "targetHandle": "{œfieldNameœ: œtoolsœ, œidœ: œAgent-H93Cvœ, œinputTypesœ: [œToolœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -149,7 +121,7 @@ "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-jHqUS", + "id": "ChatInput-7YdLP", "name": "message", "output_types": [ "Message" @@ -157,19 +129,19 @@ }, "targetHandle": { "fieldName": "input_text", - "id": "ConditionalRouter-SP1WC", + "id": "ConditionalRouter-VLPFz", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-jHqUS{œdataTypeœ:œChatInputœ,œidœ:œChatInput-jHqUSœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ConditionalRouter-SP1WC{œfieldNameœ:œinput_textœ,œidœ:œConditionalRouter-SP1WCœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-7YdLP{œdataTypeœ:œChatInputœ,œidœ:œChatInput-7YdLPœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ConditionalRouter-VLPFz{œfieldNameœ:œinput_textœ,œidœ:œConditionalRouter-VLPFzœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-jHqUS", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-jHqUSœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "ConditionalRouter-SP1WC", - "targetHandle": "{œfieldNameœ: œinput_textœ, œidœ: œConditionalRouter-SP1WCœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-7YdLP", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-7YdLPœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "ConditionalRouter-VLPFz", + "targetHandle": "{œfieldNameœ: œinput_textœ, œidœ: œConditionalRouter-VLPFzœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -177,7 +149,7 @@ "data": { "sourceHandle": { "dataType": "ChatInput", - "id": "ChatInput-jHqUS", + "id": "ChatInput-7YdLP", "name": "message", "output_types": [ "Message" @@ -185,19 +157,19 @@ }, "targetHandle": { "fieldName": "message", - "id": "ConditionalRouter-SP1WC", + "id": "ConditionalRouter-VLPFz", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ChatInput-jHqUS{œdataTypeœ:œChatInputœ,œidœ:œChatInput-jHqUSœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ConditionalRouter-SP1WC{œfieldNameœ:œmessageœ,œidœ:œConditionalRouter-SP1WCœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ChatInput-7YdLP{œdataTypeœ:œChatInputœ,œidœ:œChatInput-7YdLPœ,œnameœ:œmessageœ,œoutput_typesœ:[œMessageœ]}-ConditionalRouter-VLPFz{œfieldNameœ:œmessageœ,œidœ:œConditionalRouter-VLPFzœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ChatInput-jHqUS", - "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-jHqUSœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", - "target": "ConditionalRouter-SP1WC", - "targetHandle": "{œfieldNameœ: œmessageœ, œidœ: œConditionalRouter-SP1WCœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ChatInput-7YdLP", + "sourceHandle": "{œdataTypeœ: œChatInputœ, œidœ: œChatInput-7YdLPœ, œnameœ: œmessageœ, œoutput_typesœ: [œMessageœ]}", + "target": "ConditionalRouter-VLPFz", + "targetHandle": "{œfieldNameœ: œmessageœ, œidœ: œConditionalRouter-VLPFzœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -205,7 +177,7 @@ "data": { "sourceHandle": { "dataType": "ConditionalRouter", - "id": "ConditionalRouter-SP1WC", + "id": "ConditionalRouter-VLPFz", "name": "true_result", "output_types": [ "Message" @@ -213,19 +185,19 @@ }, "targetHandle": { "fieldName": "video_url", - "id": "YouTubeCommentsComponent-4pxuY", + "id": "YouTubeCommentsComponent-0EgiI", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ConditionalRouter-SP1WC{œdataTypeœ:œConditionalRouterœ,œidœ:œConditionalRouter-SP1WCœ,œnameœ:œtrue_resultœ,œoutput_typesœ:[œMessageœ]}-YouTubeCommentsComponent-4pxuY{œfieldNameœ:œvideo_urlœ,œidœ:œYouTubeCommentsComponent-4pxuYœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ConditionalRouter-VLPFz{œdataTypeœ:œConditionalRouterœ,œidœ:œConditionalRouter-VLPFzœ,œnameœ:œtrue_resultœ,œoutput_typesœ:[œMessageœ]}-YouTubeCommentsComponent-0EgiI{œfieldNameœ:œvideo_urlœ,œidœ:œYouTubeCommentsComponent-0EgiIœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ConditionalRouter-SP1WC", - "sourceHandle": "{œdataTypeœ: œConditionalRouterœ, œidœ: œConditionalRouter-SP1WCœ, œnameœ: œtrue_resultœ, œoutput_typesœ: [œMessageœ]}", - "target": "YouTubeCommentsComponent-4pxuY", - "targetHandle": "{œfieldNameœ: œvideo_urlœ, œidœ: œYouTubeCommentsComponent-4pxuYœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ConditionalRouter-VLPFz", + "sourceHandle": "{œdataTypeœ: œConditionalRouterœ, œidœ: œConditionalRouter-VLPFzœ, œnameœ: œtrue_resultœ, œoutput_typesœ: [œMessageœ]}", + "target": "YouTubeCommentsComponent-0EgiI", + "targetHandle": "{œfieldNameœ: œvideo_urlœ, œidœ: œYouTubeCommentsComponent-0EgiIœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -233,7 +205,7 @@ "data": { "sourceHandle": { "dataType": "ConditionalRouter", - "id": "ConditionalRouter-SP1WC", + "id": "ConditionalRouter-VLPFz", "name": "true_result", "output_types": [ "Message" @@ -241,19 +213,19 @@ }, "targetHandle": { "fieldName": "url", - "id": "Prompt-tR2a7", + "id": "Prompt-uQBug", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-ConditionalRouter-SP1WC{œdataTypeœ:œConditionalRouterœ,œidœ:œConditionalRouter-SP1WCœ,œnameœ:œtrue_resultœ,œoutput_typesœ:[œMessageœ]}-Prompt-tR2a7{œfieldNameœ:œurlœ,œidœ:œPrompt-tR2a7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-ConditionalRouter-VLPFz{œdataTypeœ:œConditionalRouterœ,œidœ:œConditionalRouter-VLPFzœ,œnameœ:œtrue_resultœ,œoutput_typesœ:[œMessageœ]}-Prompt-uQBug{œfieldNameœ:œurlœ,œidœ:œPrompt-uQBugœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "ConditionalRouter-SP1WC", - "sourceHandle": "{œdataTypeœ: œConditionalRouterœ, œidœ: œConditionalRouter-SP1WCœ, œnameœ: œtrue_resultœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-tR2a7", - "targetHandle": "{œfieldNameœ: œurlœ, œidœ: œPrompt-tR2a7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "ConditionalRouter-VLPFz", + "sourceHandle": "{œdataTypeœ: œConditionalRouterœ, œidœ: œConditionalRouter-VLPFzœ, œnameœ: œtrue_resultœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-uQBug", + "targetHandle": "{œfieldNameœ: œurlœ, œidœ: œPrompt-uQBugœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" }, { "animated": false, @@ -261,7 +233,7 @@ "data": { "sourceHandle": { "dataType": "BatchRunComponent", - "id": "BatchRunComponent-jFt7j", + "id": "BatchRunComponent-4Ou5s", "name": "batch_results", "output_types": [ "DataFrame" @@ -269,7 +241,7 @@ }, "targetHandle": { "fieldName": "input_data", - "id": "parser-LDaMh", + "id": "parser-AnsLm", "inputTypes": [ "DataFrame", "Data" @@ -277,12 +249,12 @@ "type": "other" } }, - "id": "reactflow__edge-BatchRunComponent-jFt7j{œdataTypeœ:œBatchRunComponentœ,œidœ:œBatchRunComponent-jFt7jœ,œnameœ:œbatch_resultsœ,œoutput_typesœ:[œDataFrameœ]}-parser-LDaMh{œfieldNameœ:œinput_dataœ,œidœ:œparser-LDaMhœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", + "id": "reactflow__edge-BatchRunComponent-4Ou5s{œdataTypeœ:œBatchRunComponentœ,œidœ:œBatchRunComponent-4Ou5sœ,œnameœ:œbatch_resultsœ,œoutput_typesœ:[œDataFrameœ]}-parser-AnsLm{œfieldNameœ:œinput_dataœ,œidœ:œparser-AnsLmœ,œinputTypesœ:[œDataFrameœ,œDataœ],œtypeœ:œotherœ}", "selected": false, - "source": "BatchRunComponent-jFt7j", - "sourceHandle": "{œdataTypeœ: œBatchRunComponentœ, œidœ: œBatchRunComponent-jFt7jœ, œnameœ: œbatch_resultsœ, œoutput_typesœ: [œDataFrameœ]}", - "target": "parser-LDaMh", - "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-LDaMhœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" + "source": "BatchRunComponent-4Ou5s", + "sourceHandle": "{œdataTypeœ: œBatchRunComponentœ, œidœ: œBatchRunComponent-4Ou5sœ, œnameœ: œbatch_resultsœ, œoutput_typesœ: [œDataFrameœ]}", + "target": "parser-AnsLm", + "targetHandle": "{œfieldNameœ: œinput_dataœ, œidœ: œparser-AnsLmœ, œinputTypesœ: [œDataFrameœ, œDataœ], œtypeœ: œotherœ}" }, { "animated": false, @@ -290,7 +262,7 @@ "data": { "sourceHandle": { "dataType": "parser", - "id": "parser-LDaMh", + "id": "parser-AnsLm", "name": "parsed_text", "output_types": [ "Message" @@ -298,25 +270,50 @@ }, "targetHandle": { "fieldName": "analysis", - "id": "Prompt-tR2a7", + "id": "Prompt-uQBug", "inputTypes": [ "Message" ], "type": "str" } }, - "id": "reactflow__edge-parser-LDaMh{œdataTypeœ:œparserœ,œidœ:œparser-LDaMhœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-tR2a7{œfieldNameœ:œanalysisœ,œidœ:œPrompt-tR2a7œ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", + "id": "reactflow__edge-parser-AnsLm{œdataTypeœ:œparserœ,œidœ:œparser-AnsLmœ,œnameœ:œparsed_textœ,œoutput_typesœ:[œMessageœ]}-Prompt-uQBug{œfieldNameœ:œanalysisœ,œidœ:œPrompt-uQBugœ,œinputTypesœ:[œMessageœ],œtypeœ:œstrœ}", "selected": false, - "source": "parser-LDaMh", - "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-LDaMhœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", - "target": "Prompt-tR2a7", - "targetHandle": "{œfieldNameœ: œanalysisœ, œidœ: œPrompt-tR2a7œ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + "source": "parser-AnsLm", + "sourceHandle": "{œdataTypeœ: œparserœ, œidœ: œparser-AnsLmœ, œnameœ: œparsed_textœ, œoutput_typesœ: [œMessageœ]}", + "target": "Prompt-uQBug", + "targetHandle": "{œfieldNameœ: œanalysisœ, œidœ: œPrompt-uQBugœ, œinputTypesœ: [œMessageœ], œtypeœ: œstrœ}" + }, + { + "data": { + "sourceHandle": { + "dataType": "LanguageModelComponent", + "id": "LanguageModelComponent-dYtAT", + "name": "model_output", + "output_types": [ + "LanguageModel" + ] + }, + "targetHandle": { + "fieldName": "model", + "id": "BatchRunComponent-4Ou5s", + "inputTypes": [ + "LanguageModel" + ], + "type": "other" + } + }, + "id": "xy-edge__LanguageModelComponent-dYtAT{œdataTypeœ:œLanguageModelComponentœ,œidœ:œLanguageModelComponent-dYtATœ,œnameœ:œmodel_outputœ,œoutput_typesœ:[œLanguageModelœ]}-BatchRunComponent-4Ou5s{œfieldNameœ:œmodelœ,œidœ:œBatchRunComponent-4Ou5sœ,œinputTypesœ:[œLanguageModelœ],œtypeœ:œotherœ}", + "source": "LanguageModelComponent-dYtAT", + "sourceHandle": "{œdataTypeœ: œLanguageModelComponentœ, œidœ: œLanguageModelComponent-dYtATœ, œnameœ: œmodel_outputœ, œoutput_typesœ: [œLanguageModelœ]}", + "target": "BatchRunComponent-4Ou5s", + "targetHandle": "{œfieldNameœ: œmodelœ, œidœ: œBatchRunComponent-4Ou5sœ, œinputTypesœ: [œLanguageModelœ], œtypeœ: œotherœ}" } ], "nodes": [ { "data": { - "id": "BatchRunComponent-jFt7j", + "id": "BatchRunComponent-4Ou5s", "node": { "base_classes": [ "DataFrame" @@ -515,7 +512,7 @@ "type": "BatchRunComponent" }, "dragging": false, - "id": "BatchRunComponent-jFt7j", + "id": "BatchRunComponent-4Ou5s", "measured": { "height": 391, "width": 320 @@ -529,7 +526,7 @@ }, { "data": { - "id": "YouTubeCommentsComponent-4pxuY", + "id": "YouTubeCommentsComponent-0EgiI", "node": { "base_classes": [ "DataFrame" @@ -721,7 +718,7 @@ "type": "YouTubeCommentsComponent" }, "dragging": false, - "id": "YouTubeCommentsComponent-4pxuY", + "id": "YouTubeCommentsComponent-0EgiI", "measured": { "height": 467, "width": 320 @@ -735,404 +732,12 @@ }, { "data": { - "id": "OpenAIModel-3klNa", - "node": { - "base_classes": [ - "LanguageModel", - "Message" - ], - "beta": false, - "category": "models", - "conditional_paths": [], - "custom_fields": {}, - "description": "Generates text using OpenAI LLMs.", - "display_name": "OpenAI", - "documentation": "", - "edited": false, - "field_order": [ - "input_value", - "system_message", - "stream", - "max_tokens", - "model_kwargs", - "json_mode", - "model_name", - "openai_api_base", - "api_key", - "temperature", - "seed" - ], - "frozen": false, - "icon": "OpenAI", - "key": "OpenAIModel", - "legacy": false, - "lf_version": "1.4.2", - "metadata": { - "keywords": [ - "model", - "llm", - "language model", - "large language model" - ] - }, - "minimized": false, - "output_types": [], - "outputs": [ - { - "allows_loop": false, - "cache": true, - "display_name": "Model Response", - "group_outputs": false, - "method": "text_response", - "name": "text_output", - "selected": "Message", - "tool_mode": true, - "types": [ - "Message" - ], - "value": "__UNDEFINED__" - }, - { - "allows_loop": false, - "cache": true, - "display_name": "Language Model", - "group_outputs": false, - "method": "build_model", - "name": "model_output", - "selected": "LanguageModel", - "tool_mode": true, - "types": [ - "LanguageModel" - ], - "value": "__UNDEFINED__" - } - ], - "pinned": false, - "score": 0.001, - "template": { - "_type": "Component", - "api_key": { - "_input_type": "SecretStrInput", - "advanced": false, - "display_name": "OpenAI API Key", - "dynamic": false, - "info": "The OpenAI API Key to use for the OpenAI model.", - "input_types": [], - "load_from_db": true, - "name": "api_key", - "password": true, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "str", - "value": "" - }, - "code": { - "advanced": true, - "dynamic": true, - "fileTypes": [], - "file_path": "", - "info": "", - "list": false, - "load_from_db": false, - "multiline": true, - "name": "code", - "password": false, - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "type": "code", - "value": "from typing import Any\n\nfrom langchain_openai import ChatOpenAI\nfrom pydantic.v1 import SecretStr\n\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import (\n OPENAI_MODEL_NAMES,\n OPENAI_REASONING_MODEL_NAMES,\n)\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput, DictInput, DropdownInput, IntInput, SecretStrInput, SliderInput, StrInput\nfrom langflow.logging import logger\n\n\nclass OpenAIModelComponent(LCModelComponent):\n display_name = \"OpenAI\"\n description = \"Generates text using OpenAI LLMs.\"\n icon = \"OpenAI\"\n name = \"OpenAIModel\"\n\n inputs = [\n *LCModelComponent._base_inputs,\n IntInput(\n name=\"max_tokens\",\n display_name=\"Max Tokens\",\n advanced=True,\n info=\"The maximum number of tokens to generate. Set to 0 for unlimited tokens.\",\n range_spec=RangeSpec(min=0, max=128000),\n ),\n DictInput(\n name=\"model_kwargs\",\n display_name=\"Model Kwargs\",\n advanced=True,\n info=\"Additional keyword arguments to pass to the model.\",\n ),\n BoolInput(\n name=\"json_mode\",\n display_name=\"JSON Mode\",\n advanced=True,\n info=\"If True, it will output JSON regardless of passing a schema.\",\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n advanced=False,\n options=OPENAI_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[1],\n combobox=True,\n real_time_refresh=True,\n ),\n StrInput(\n name=\"openai_api_base\",\n display_name=\"OpenAI API Base\",\n advanced=True,\n info=\"The base URL of the OpenAI API. \"\n \"Defaults to https://api.openai.com/v1. \"\n \"You can change this to use other APIs like JinaChat, LocalAI and Prem.\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"The OpenAI API Key to use for the OpenAI model.\",\n advanced=False,\n value=\"OPENAI_API_KEY\",\n required=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n show=True,\n ),\n IntInput(\n name=\"seed\",\n display_name=\"Seed\",\n info=\"The seed controls the reproducibility of the job.\",\n advanced=True,\n value=1,\n ),\n IntInput(\n name=\"max_retries\",\n display_name=\"Max Retries\",\n info=\"The maximum number of retries to make when generating.\",\n advanced=True,\n value=5,\n ),\n IntInput(\n name=\"timeout\",\n display_name=\"Timeout\",\n info=\"The timeout for requests to OpenAI completion API.\",\n advanced=True,\n value=700,\n ),\n ]\n\n def build_model(self) -> LanguageModel: # type: ignore[type-var]\n parameters = {\n \"api_key\": SecretStr(self.api_key).get_secret_value() if self.api_key else None,\n \"model_name\": self.model_name,\n \"max_tokens\": self.max_tokens or None,\n \"model_kwargs\": self.model_kwargs or {},\n \"base_url\": self.openai_api_base or \"https://api.openai.com/v1\",\n \"seed\": self.seed,\n \"max_retries\": self.max_retries,\n \"timeout\": self.timeout,\n \"temperature\": self.temperature if self.temperature is not None else 0.1,\n }\n\n logger.info(f\"Model name: {self.model_name}\")\n if self.model_name in OPENAI_REASONING_MODEL_NAMES:\n logger.info(\"Getting reasoning model parameters\")\n parameters.pop(\"temperature\")\n parameters.pop(\"seed\")\n output = ChatOpenAI(**parameters)\n if self.json_mode:\n output = output.bind(response_format={\"type\": \"json_object\"})\n\n return output\n\n def _get_exception_message(self, e: Exception):\n \"\"\"Get a message from an OpenAI exception.\n\n Args:\n e (Exception): The exception to get the message from.\n\n Returns:\n str: The message from the exception.\n \"\"\"\n try:\n from openai import BadRequestError\n except ImportError:\n return None\n if isinstance(e, BadRequestError):\n message = e.body.get(\"message\")\n if message:\n return message\n return None\n\n def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_REASONING_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = False\n build_config[\"seed\"][\"show\"] = False\n if field_name in {\"base_url\", \"model_name\", \"api_key\"} and field_value in OPENAI_MODEL_NAMES:\n build_config[\"temperature\"][\"show\"] = True\n build_config[\"seed\"][\"show\"] = True\n return build_config\n" - }, - "input_value": { - "_input_type": "MessageInput", - "advanced": false, - "display_name": "Input", - "dynamic": false, - "info": "", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "input_value", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "json_mode": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "JSON Mode", - "dynamic": false, - "info": "If True, it will output JSON regardless of passing a schema.", - "list": false, - "list_add_label": "Add More", - "name": "json_mode", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "max_retries": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Retries", - "dynamic": false, - "info": "The maximum number of retries to make when generating.", - "list": false, - "list_add_label": "Add More", - "name": "max_retries", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 5 - }, - "max_tokens": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Max Tokens", - "dynamic": false, - "info": "The maximum number of tokens to generate. Set to 0 for unlimited tokens.", - "list": false, - "list_add_label": "Add More", - "name": "max_tokens", - "placeholder": "", - "range_spec": { - "max": 128000, - "min": 0, - "step": 0.1, - "step_type": "float" - }, - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": "" - }, - "model_kwargs": { - "_input_type": "DictInput", - "advanced": true, - "display_name": "Model Kwargs", - "dynamic": false, - "info": "Additional keyword arguments to pass to the model.", - "list": false, - "list_add_label": "Add More", - "name": "model_kwargs", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "type": "dict", - "value": {} - }, - "model_name": { - "_input_type": "DropdownInput", - "advanced": false, - "combobox": true, - "dialog_inputs": {}, - "display_name": "Model Name", - "dynamic": false, - "info": "", - "name": "model_name", - "options": [ - "gpt-4o-mini", - "gpt-4o", - "gpt-4.1", - "gpt-4.1-mini", - "gpt-4.1-nano", - "gpt-4.5-preview", - "gpt-4-turbo", - "gpt-4-turbo-preview", - "gpt-4", - "gpt-3.5-turbo", - "o1" - ], - "options_metadata": [], - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "gpt-4.1-mini" - }, - "openai_api_base": { - "_input_type": "StrInput", - "advanced": true, - "display_name": "OpenAI API Base", - "dynamic": false, - "info": "The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.", - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "name": "openai_api_base", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "seed": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Seed", - "dynamic": false, - "info": "The seed controls the reproducibility of the job.", - "list": false, - "list_add_label": "Add More", - "name": "seed", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 1 - }, - "stream": { - "_input_type": "BoolInput", - "advanced": true, - "display_name": "Stream", - "dynamic": false, - "info": "Stream the response from the model. Streaming works only in Chat.", - "list": false, - "list_add_label": "Add More", - "name": "stream", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "bool", - "value": false - }, - "system_message": { - "_input_type": "MultilineInput", - "advanced": false, - "display_name": "System Message", - "dynamic": false, - "info": "System message to pass to the model.", - "input_types": [ - "Message" - ], - "list": false, - "list_add_label": "Add More", - "load_from_db": false, - "multiline": true, - "name": "system_message", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "temperature": { - "_input_type": "SliderInput", - "advanced": false, - "display_name": "Temperature", - "dynamic": false, - "info": "", - "max_label": "", - "max_label_icon": "", - "min_label": "", - "min_label_icon": "", - "name": "temperature", - "placeholder": "", - "range_spec": { - "max": 2, - "min": 0, - "step": 0.01, - "step_type": "float" - }, - "required": false, - "show": true, - "slider_buttons": false, - "slider_buttons_options": [], - "slider_input": false, - "title_case": false, - "tool_mode": false, - "type": "slider", - "value": 0.1 - }, - "timeout": { - "_input_type": "IntInput", - "advanced": true, - "display_name": "Timeout", - "dynamic": false, - "info": "The timeout for requests to OpenAI completion API.", - "list": false, - "list_add_label": "Add More", - "name": "timeout", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "tool_mode": false, - "trace_as_metadata": true, - "type": "int", - "value": 700 - } - }, - "tool_mode": false - }, - "selected_output": "model_output", - "showNode": true, - "type": "OpenAIModel" - }, - "dragging": false, - "id": "OpenAIModel-3klNa", - "measured": { - "height": 540, - "width": 320 - }, - "position": { - "x": 192.79820011992825, - "y": 5360.663143346016 - }, - "selected": false, - "type": "genericNode" - }, - { - "data": { - "id": "Agent-A37q9", + "id": "Agent-H93Cv", "node": { "base_classes": [ "Message" ], "beta": false, - "category": "agents", "conditional_paths": [], "custom_fields": {}, "description": "Define the agent's instructions, then enter a task to complete using tools.", @@ -1149,27 +754,21 @@ "api_key", "temperature", "seed", + "max_retries", + "timeout", "system_prompt", + "n_messages", "tools", "input_value", "handle_parsing_errors", "verbose", "max_iterations", "agent_description", - "memory", - "sender", - "sender_name", - "n_messages", - "session_id", - "order", - "template", "add_current_date_tool" ], "frozen": false, "icon": "bot", - "key": "Agent", "legacy": false, - "lf_version": "1.1.3", "metadata": {}, "minimized": false, "output_types": [], @@ -1178,8 +777,12 @@ "allows_loop": false, "cache": true, "display_name": "Response", + "group_outputs": false, + "hidden": null, "method": "message_response", "name": "response", + "options": null, + "required_inputs": null, "selected": "Message", "tool_mode": true, "types": [ @@ -1189,7 +792,6 @@ } ], "pinned": false, - "score": 1.1732828199964098e-19, "template": { "_type": "Component", "add_current_date_tool": { @@ -1213,6 +815,7 @@ "agent_description": { "_input_type": "MultilineInput", "advanced": true, + "copy_field": false, "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", @@ -1251,12 +854,29 @@ "OpenAI", "Custom" ], - "options_metadata": [], + "options_metadata": [ + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + }, + { + "icon": "Groq" + }, + { + "icon": "OpenAI" + }, + { + "icon": "brain" + } + ], "placeholder": "", "real_time_refresh": true, "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1269,10 +889,11 @@ "dynamic": false, "info": "The OpenAI API Key to use for the OpenAI model.", "input_types": [], - "load_from_db": true, + "load_from_db": false, "name": "api_key", "password": true, "placeholder": "", + "real_time_refresh": true, "required": true, "show": true, "title_case": false, @@ -1295,7 +916,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODEL_PROVIDERS)] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n *LCToolsAgentComponent._base_inputs,\n *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n memory_kwargs = {\n component_input.name: getattr(self, f\"{component_input.name}\") for component_input in self.memory_inputs\n }\n # filter out empty values\n memory_kwargs = {k: v for k, v in memory_kwargs.items() if v is not None}\n\n return await MemoryComponent(**self.get_base_args()).set(**memory_kwargs).retrieve_messages()\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" + "value": "from langchain_core.tools import StructuredTool\n\nfrom langflow.base.agents.agent import LCToolsAgentComponent\nfrom langflow.base.agents.events import ExceptionWithMessageError\nfrom langflow.base.models.model_input_constants import (\n ALL_PROVIDER_FIELDS,\n MODEL_DYNAMIC_UPDATE_FIELDS,\n MODEL_PROVIDERS,\n MODEL_PROVIDERS_DICT,\n MODELS_METADATA,\n)\nfrom langflow.base.models.model_utils import get_model_name\nfrom langflow.components.helpers.current_date import CurrentDateComponent\nfrom langflow.components.helpers.memory import MemoryComponent\nfrom langflow.components.langchain_utilities.tool_calling import ToolCallingAgentComponent\nfrom langflow.custom.custom_component.component import _get_component_toolkit\nfrom langflow.custom.utils import update_component_build_config\nfrom langflow.field_typing import Tool\nfrom langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output\nfrom langflow.logging import logger\nfrom langflow.schema.dotdict import dotdict\nfrom langflow.schema.message import Message\n\n\ndef set_advanced_true(component_input):\n component_input.advanced = True\n return component_input\n\n\nMODEL_PROVIDERS_LIST = [\"Anthropic\", \"Google Generative AI\", \"Groq\", \"OpenAI\"]\n\n\nclass AgentComponent(ToolCallingAgentComponent):\n display_name: str = \"Agent\"\n description: str = \"Define the agent's instructions, then enter a task to complete using tools.\"\n icon = \"bot\"\n beta = False\n name = \"Agent\"\n\n memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]\n\n inputs = [\n DropdownInput(\n name=\"agent_llm\",\n display_name=\"Model Provider\",\n info=\"The provider of the language model that the agent will use to generate responses.\",\n options=[*MODEL_PROVIDERS_LIST, \"Custom\"],\n value=\"OpenAI\",\n real_time_refresh=True,\n input_types=[],\n options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{\"icon\": \"brain\"}],\n ),\n *MODEL_PROVIDERS_DICT[\"OpenAI\"][\"inputs\"],\n MultilineInput(\n name=\"system_prompt\",\n display_name=\"Agent Instructions\",\n info=\"System Prompt: Initial instructions and context provided to guide the agent's behavior.\",\n value=\"You are a helpful assistant that can use tools to answer questions and perform tasks.\",\n advanced=False,\n ),\n IntInput(\n name=\"n_messages\",\n display_name=\"Number of Chat History Messages\",\n value=100,\n info=\"Number of chat history messages to retrieve.\",\n advanced=True,\n show=True,\n ),\n *LCToolsAgentComponent._base_inputs,\n # removed memory inputs from agent component\n # *memory_inputs,\n BoolInput(\n name=\"add_current_date_tool\",\n display_name=\"Current Date\",\n advanced=True,\n info=\"If true, will add a tool to the agent that returns the current date.\",\n value=True,\n ),\n ]\n outputs = [Output(name=\"response\", display_name=\"Response\", method=\"message_response\")]\n\n async def message_response(self) -> Message:\n try:\n # Get LLM model and validate\n llm_model, display_name = self.get_llm()\n if llm_model is None:\n msg = \"No language model selected. Please choose a model to proceed.\"\n raise ValueError(msg)\n self.model_name = get_model_name(llm_model, display_name=display_name)\n\n # Get memory data\n self.chat_history = await self.get_memory_data()\n if isinstance(self.chat_history, Message):\n self.chat_history = [self.chat_history]\n\n # Add current date tool if enabled\n if self.add_current_date_tool:\n if not isinstance(self.tools, list): # type: ignore[has-type]\n self.tools = []\n current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)\n if not isinstance(current_date_tool, StructuredTool):\n msg = \"CurrentDateComponent must be converted to a StructuredTool\"\n raise TypeError(msg)\n self.tools.append(current_date_tool)\n # note the tools are not required to run the agent, hence the validation removed.\n\n # Set up and run agent\n self.set(\n llm=llm_model,\n tools=self.tools or [],\n chat_history=self.chat_history,\n input_value=self.input_value,\n system_prompt=self.system_prompt,\n )\n agent = self.create_agent_runnable()\n return await self.run_agent(agent)\n\n except (ValueError, TypeError, KeyError) as e:\n logger.error(f\"{type(e).__name__}: {e!s}\")\n raise\n except ExceptionWithMessageError as e:\n logger.error(f\"ExceptionWithMessageError occurred: {e}\")\n raise\n except Exception as e:\n logger.error(f\"Unexpected error: {e!s}\")\n raise\n\n async def get_memory_data(self):\n return (\n await MemoryComponent(**self.get_base_args())\n .set(session_id=self.graph.session_id, order=\"Ascending\", n_messages=self.n_messages)\n .retrieve_messages()\n )\n\n def get_llm(self):\n if not isinstance(self.agent_llm, str):\n return self.agent_llm, None\n\n try:\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if not provider_info:\n msg = f\"Invalid model provider: {self.agent_llm}\"\n raise ValueError(msg)\n\n component_class = provider_info.get(\"component_class\")\n display_name = component_class.display_name\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\", \"\")\n\n return self._build_llm_model(component_class, inputs, prefix), display_name\n\n except Exception as e:\n logger.error(f\"Error building {self.agent_llm} language model: {e!s}\")\n msg = f\"Failed to initialize language model: {e!s}\"\n raise ValueError(msg) from e\n\n def _build_llm_model(self, component, inputs, prefix=\"\"):\n model_kwargs = {}\n for input_ in inputs:\n if hasattr(self, f\"{prefix}{input_.name}\"):\n model_kwargs[input_.name] = getattr(self, f\"{prefix}{input_.name}\")\n return component.set(**model_kwargs).build_model()\n\n def set_component_params(self, component):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n inputs = provider_info.get(\"inputs\")\n prefix = provider_info.get(\"prefix\")\n model_kwargs = {input_.name: getattr(self, f\"{prefix}{input_.name}\") for input_ in inputs}\n\n return component.set(**model_kwargs)\n return component\n\n def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:\n \"\"\"Delete specified fields from build_config.\"\"\"\n for field in fields:\n build_config.pop(field, None)\n\n def update_input_types(self, build_config: dotdict) -> dotdict:\n \"\"\"Update input types for all fields in build_config.\"\"\"\n for key, value in build_config.items():\n if isinstance(value, dict):\n if value.get(\"input_types\") is None:\n build_config[key][\"input_types\"] = []\n elif hasattr(value, \"input_types\") and value.input_types is None:\n value.input_types = []\n return build_config\n\n async def update_build_config(\n self, build_config: dotdict, field_value: str, field_name: str | None = None\n ) -> dotdict:\n # Iterate over all providers in the MODEL_PROVIDERS_DICT\n # Existing logic for updating build_config\n if field_name in (\"agent_llm\",):\n build_config[\"agent_llm\"][\"value\"] = field_value\n provider_info = MODEL_PROVIDERS_DICT.get(field_value)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call the component class's update_build_config method\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n\n provider_configs: dict[str, tuple[dict, list[dict]]] = {\n provider: (\n MODEL_PROVIDERS_DICT[provider][\"fields\"],\n [\n MODEL_PROVIDERS_DICT[other_provider][\"fields\"]\n for other_provider in MODEL_PROVIDERS_DICT\n if other_provider != provider\n ],\n )\n for provider in MODEL_PROVIDERS_DICT\n }\n if field_value in provider_configs:\n fields_to_add, fields_to_delete = provider_configs[field_value]\n\n # Delete fields from other providers\n for fields in fields_to_delete:\n self.delete_fields(build_config, fields)\n\n # Add provider-specific fields\n if field_value == \"OpenAI\" and not any(field in build_config for field in fields_to_add):\n build_config.update(fields_to_add)\n else:\n build_config.update(fields_to_add)\n # Reset input types for agent_llm\n build_config[\"agent_llm\"][\"input_types\"] = []\n elif field_value == \"Custom\":\n # Delete all provider fields\n self.delete_fields(build_config, ALL_PROVIDER_FIELDS)\n # Update with custom component\n custom_component = DropdownInput(\n name=\"agent_llm\",\n display_name=\"Language Model\",\n options=[*sorted(MODEL_PROVIDERS), \"Custom\"],\n value=\"Custom\",\n real_time_refresh=True,\n input_types=[\"LanguageModel\"],\n options_metadata=[MODELS_METADATA[key] for key in sorted(MODELS_METADATA.keys())]\n + [{\"icon\": \"brain\"}],\n )\n build_config.update({\"agent_llm\": custom_component.to_dict()})\n # Update input types for all fields\n build_config = self.update_input_types(build_config)\n\n # Validate required keys\n default_keys = [\n \"code\",\n \"_type\",\n \"agent_llm\",\n \"tools\",\n \"input_value\",\n \"add_current_date_tool\",\n \"system_prompt\",\n \"agent_description\",\n \"max_iterations\",\n \"handle_parsing_errors\",\n \"verbose\",\n ]\n missing_keys = [key for key in default_keys if key not in build_config]\n if missing_keys:\n msg = f\"Missing required keys in build_config: {missing_keys}\"\n raise ValueError(msg)\n if (\n isinstance(self.agent_llm, str)\n and self.agent_llm in MODEL_PROVIDERS_DICT\n and field_name in MODEL_DYNAMIC_UPDATE_FIELDS\n ):\n provider_info = MODEL_PROVIDERS_DICT.get(self.agent_llm)\n if provider_info:\n component_class = provider_info.get(\"component_class\")\n component_class = self.set_component_params(component_class)\n prefix = provider_info.get(\"prefix\")\n if component_class and hasattr(component_class, \"update_build_config\"):\n # Call each component class's update_build_config method\n # remove the prefix from the field_name\n if isinstance(field_name, str) and isinstance(prefix, str):\n field_name = field_name.replace(prefix, \"\")\n build_config = await update_component_build_config(\n component_class, build_config, field_value, \"model_name\"\n )\n return dotdict({k: v.to_dict() if hasattr(v, \"to_dict\") else v for k, v in build_config.items()})\n\n async def _get_tools(self) -> list[Tool]:\n component_toolkit = _get_component_toolkit()\n tools_names = self._build_tools_names()\n agent_description = self.get_tool_description()\n # TODO: Agent Description Depreciated Feature to be removed\n description = f\"{agent_description}{tools_names}\"\n tools = component_toolkit(component=self).get_tools(\n tool_name=\"Call_Agent\", tool_description=description, callbacks=self.get_langchain_callbacks()\n )\n if hasattr(self, \"tools_metadata\"):\n tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)\n return tools\n" }, "handle_parsing_errors": { "_input_type": "BoolInput", @@ -1416,70 +1037,6 @@ "type": "int", "value": "" }, - "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, - "list_add_label": "Add More", - "name": "memory", - "placeholder": "", - "required": false, - "show": true, - "title_case": false, - "trace_as_metadata": true, - "type": "other", - "value": "" - }, - "message": { - "_input_type": "MessageTextInput", - "advanced": true, - "display_name": "Message", - "dynamic": false, - "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": true, - "title_case": false, - "tool_mode": true, - "trace_as_input": true, - "trace_as_metadata": true, - "type": "str", - "value": "" - }, - "mode": { - "_input_type": "TabInput", - "advanced": true, - "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": "Store" - }, "model_kwargs": { "_input_type": "DictInput", "advanced": true, @@ -1506,6 +1063,7 @@ "display_name": "Model Name", "dynamic": false, "info": "To see the model names, first choose a provider. Then, enter your API key and click the refresh button next to the model name.", + "load_from_db": false, "name": "model_name", "options": [ "gpt-4o-mini", @@ -1526,6 +1084,7 @@ "required": false, "show": true, "title_case": false, + "toggle": false, "tool_mode": false, "trace_as_metadata": true, "type": "str", @@ -1534,9 +1093,9 @@ "n_messages": { "_input_type": "IntInput", "advanced": true, - "display_name": "Number of Messages", + "display_name": "Number of Chat History Messages", "dynamic": false, - "info": "Number of messages to retrieve.", + "info": "Number of chat history messages to retrieve.", "list": false, "list_add_label": "Add More", "name": "n_messages", @@ -1568,29 +1127,6 @@ "type": "str", "value": "" }, - "order": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Order", - "dynamic": false, - "info": "Order of the messages.", - "name": "order", - "options": [ - "Ascending", - "Descending" - ], - "options_metadata": [], - "placeholder": "", - "required": true, - "show": true, - "title_case": false, - "tool_mode": true, - "trace_as_metadata": true, - "type": "str", - "value": "Ascending" - }, "seed": { "_input_type": "IntInput", "advanced": true, @@ -1609,104 +1145,10 @@ "type": "int", "value": 1 }, - "sender": { - "_input_type": "DropdownInput", - "advanced": true, - "combobox": false, - "dialog_inputs": {}, - "display_name": "Sender", - "dynamic": false, - "info": "The sender of the message. Might be Machine or User. If empty, the current sender parameter will be used.", - "name": "sender", - "options": [ - "Machine", - "User", - "Machine and User" - ], - "options_metadata": [], - "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, - "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": "" - }, - "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, - "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": "" - }, "system_prompt": { "_input_type": "MultilineInput", "advanced": false, + "copy_field": false, "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", @@ -1741,7 +1183,7 @@ "name": "temperature", "placeholder": "", "range_spec": { - "max": 2, + "max": 1, "min": 0, "step": 0.01, "step_type": "float" @@ -1756,30 +1198,6 @@ "type": "slider", "value": 0.1 }, - "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, - "list_add_label": "Add More", - "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}" - }, "timeout": { "_input_type": "IntInput", "advanced": true, @@ -1844,7 +1262,7 @@ "type": "Agent" }, "dragging": false, - "id": "Agent-A37q9", + "id": "Agent-H93Cv", "measured": { "height": 594, "width": 320 @@ -1858,7 +1276,7 @@ }, { "data": { - "id": "Prompt-tR2a7", + "id": "Prompt-uQBug", "node": { "base_classes": [ "Message" @@ -2022,7 +1440,7 @@ "type": "Prompt" }, "dragging": false, - "id": "Prompt-tR2a7", + "id": "Prompt-uQBug", "measured": { "height": 449, "width": 320 @@ -2036,7 +1454,7 @@ }, { "data": { - "id": "ChatOutput-w4PAC", + "id": "ChatOutput-rRSvO", "node": { "base_classes": [ "Message" @@ -2335,7 +1753,7 @@ "type": "ChatOutput" }, "dragging": false, - "id": "ChatOutput-w4PAC", + "id": "ChatOutput-rRSvO", "measured": { "height": 204, "width": 320 @@ -2349,7 +1767,7 @@ }, { "data": { - "id": "YouTubeTranscripts-Nbrx3", + "id": "YouTubeTranscripts-eg1lO", "node": { "base_classes": [ "Data", @@ -2573,7 +1991,7 @@ "type": "YouTubeTranscripts" }, "dragging": false, - "id": "YouTubeTranscripts-Nbrx3", + "id": "YouTubeTranscripts-eg1lO", "measured": { "height": 328, "width": 320 @@ -2587,7 +2005,7 @@ }, { "data": { - "id": "ChatInput-jHqUS", + "id": "ChatInput-7YdLP", "node": { "base_classes": [ "Message" @@ -2887,7 +2305,7 @@ "type": "ChatInput" }, "dragging": false, - "id": "ChatInput-jHqUS", + "id": "ChatInput-7YdLP", "measured": { "height": 204, "width": 320 @@ -2901,7 +2319,7 @@ }, { "data": { - "id": "note-UUFzO", + "id": "note-GRvKY", "node": { "description": "# Batch Run component\n\nThis component processes a DataFrame by running each row through a Language Model (LLM). Perfect for batch analysis, sentiment scoring, or content generation at scale.\n\n## How It Works\n1. Accepts a DataFrame with text data.\n2. Routes each row through your chosen LLM.\n3. Returns new DataFrame with `text_input` and `model_response`.\n\n", "display_name": "", @@ -2914,10 +2332,10 @@ }, "dragging": false, "height": 522, - "id": "note-UUFzO", + "id": "note-GRvKY", "measured": { "height": 522, - "width": 325 + "width": 324 }, "position": { "x": 631.7137680312561, @@ -2930,7 +2348,7 @@ }, { "data": { - "id": "note-sqTuK", + "id": "note-E1WRc", "node": { "description": "## Set up the YouTube API\n1. Go to [Google Cloud Console](https://console.cloud.google.com).\n2. Create a new project or select existing one.\n3. Enable YouTube Data API v3:\n - Navigate to APIs & Services > Library.\n - Search \"YouTube Data API v3\".\n - Click Enable.\n4. Create credentials:\n - Go to APIs & Services > Credentials.\n - Click Create Credentials > API Key.\n5. Copy your new API key for use in the component.\n\n⚠️ Remember to:\n- Restrict the API key to YouTube Data API v3 only.\n- Set appropriate quotas and restrictions.\n", "display_name": "", @@ -2943,10 +2361,10 @@ }, "dragging": false, "height": 486, - "id": "note-sqTuK", + "id": "note-E1WRc", "measured": { "height": 486, - "width": 325 + "width": 324 }, "position": { "x": 1579.119903578572, @@ -2959,7 +2377,7 @@ }, { "data": { - "id": "note-Di19o", + "id": "note-MTqvg", "node": { "description": "# 🎥 YouTube Video Analysis\nThis flow performs comprehensive analysis of YouTube videos.\n1. Extract video comments and transcripts.\n2. Run sentiment analysis on comments using LLM.\n3. Combine transcript content and comment sentiment for comprehensive video analysis.\n\n## Prerequisites\n- OpenAI API Key\n- YouTube Data API v3 key", "display_name": "", @@ -2972,10 +2390,10 @@ }, "dragging": false, "height": 454, - "id": "note-Di19o", + "id": "note-MTqvg", "measured": { "height": 454, - "width": 433 + "width": 432 }, "position": { "x": -1366.105596485301, @@ -2988,7 +2406,7 @@ }, { "data": { - "id": "ConditionalRouter-SP1WC", + "id": "ConditionalRouter-VLPFz", "node": { "base_classes": [ "Message" @@ -3234,7 +2652,7 @@ "type": "ConditionalRouter" }, "dragging": false, - "id": "ConditionalRouter-SP1WC", + "id": "ConditionalRouter-VLPFz", "measured": { "height": 429, "width": 320 @@ -3248,7 +2666,7 @@ }, { "data": { - "id": "parser-LDaMh", + "id": "parser-AnsLm", "node": { "base_classes": [ "Message" @@ -3409,7 +2827,7 @@ "type": "parser" }, "dragging": false, - "id": "parser-LDaMh", + "id": "parser-AnsLm", "measured": { "height": 361, "width": 320 @@ -3420,19 +2838,314 @@ }, "selected": false, "type": "genericNode" + }, + { + "data": { + "id": "LanguageModelComponent-dYtAT", + "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, + "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": "OpenAI API Key", + "dynamic": false, + "info": "Model Provider API key", + "input_types": [], + "load_from_db": false, + "name": "api_key", + "password": true, + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "type": "str", + "value": "" + }, + "code": { + "advanced": true, + "dynamic": true, + "fileTypes": [], + "file_path": "", + "info": "", + "list": false, + "load_from_db": false, + "multiline": true, + "name": "code", + "password": false, + "placeholder": "", + "required": true, + "show": true, + "title_case": false, + "type": "code", + "value": "from typing import Any\n\nfrom langchain_anthropic import ChatAnthropic\nfrom langchain_google_genai import ChatGoogleGenerativeAI\nfrom langchain_openai import ChatOpenAI\n\nfrom langflow.base.models.anthropic_constants import ANTHROPIC_MODELS\nfrom langflow.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS\nfrom langflow.base.models.model import LCModelComponent\nfrom langflow.base.models.openai_constants import OPENAI_MODEL_NAMES\nfrom langflow.field_typing import LanguageModel\nfrom langflow.field_typing.range_spec import RangeSpec\nfrom langflow.inputs.inputs import BoolInput\nfrom langflow.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput\nfrom langflow.schema.dotdict import dotdict\n\n\nclass LanguageModelComponent(LCModelComponent):\n display_name = \"Language Model\"\n description = \"Runs a language model given a specified provider. \"\n icon = \"brain-circuit\"\n category = \"models\"\n priority = 0 # Set priority to 0 to make it appear first\n\n inputs = [\n DropdownInput(\n name=\"provider\",\n display_name=\"Model Provider\",\n options=[\"OpenAI\", \"Anthropic\", \"Google\"],\n value=\"OpenAI\",\n info=\"Select the model provider\",\n real_time_refresh=True,\n options_metadata=[{\"icon\": \"OpenAI\"}, {\"icon\": \"Anthropic\"}, {\"icon\": \"GoogleGenerativeAI\"}],\n ),\n DropdownInput(\n name=\"model_name\",\n display_name=\"Model Name\",\n options=OPENAI_MODEL_NAMES,\n value=OPENAI_MODEL_NAMES[0],\n info=\"Select the model to use\",\n ),\n SecretStrInput(\n name=\"api_key\",\n display_name=\"OpenAI API Key\",\n info=\"Model Provider API key\",\n required=False,\n show=True,\n real_time_refresh=True,\n ),\n MessageInput(\n name=\"input_value\",\n display_name=\"Input\",\n info=\"The input text to send to the model\",\n ),\n MultilineInput(\n name=\"system_message\",\n display_name=\"System Message\",\n info=\"A system message that helps set the behavior of the assistant\",\n advanced=True,\n ),\n BoolInput(\n name=\"stream\",\n display_name=\"Stream\",\n info=\"Whether to stream the response\",\n value=False,\n advanced=True,\n ),\n SliderInput(\n name=\"temperature\",\n display_name=\"Temperature\",\n value=0.1,\n info=\"Controls randomness in responses\",\n range_spec=RangeSpec(min=0, max=1, step=0.01),\n advanced=True,\n ),\n ]\n\n def build_model(self) -> LanguageModel:\n provider = self.provider\n model_name = self.model_name\n temperature = self.temperature\n stream = self.stream\n\n if provider == \"OpenAI\":\n if not self.api_key:\n msg = \"OpenAI API key is required when using OpenAI provider\"\n raise ValueError(msg)\n return ChatOpenAI(\n model_name=model_name,\n temperature=temperature,\n streaming=stream,\n openai_api_key=self.api_key,\n )\n if provider == \"Anthropic\":\n if not self.api_key:\n msg = \"Anthropic API key is required when using Anthropic provider\"\n raise ValueError(msg)\n return ChatAnthropic(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n anthropic_api_key=self.api_key,\n )\n if provider == \"Google\":\n if not self.api_key:\n msg = \"Google API key is required when using Google provider\"\n raise ValueError(msg)\n return ChatGoogleGenerativeAI(\n model=model_name,\n temperature=temperature,\n streaming=stream,\n google_api_key=self.api_key,\n )\n msg = f\"Unknown provider: {provider}\"\n raise ValueError(msg)\n\n def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None) -> dotdict:\n if field_name == \"provider\":\n if field_value == \"OpenAI\":\n build_config[\"model_name\"][\"options\"] = OPENAI_MODEL_NAMES\n build_config[\"model_name\"][\"value\"] = OPENAI_MODEL_NAMES[0]\n build_config[\"api_key\"][\"display_name\"] = \"OpenAI API Key\"\n elif field_value == \"Anthropic\":\n build_config[\"model_name\"][\"options\"] = ANTHROPIC_MODELS\n build_config[\"model_name\"][\"value\"] = ANTHROPIC_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Anthropic API Key\"\n elif field_value == \"Google\":\n build_config[\"model_name\"][\"options\"] = GOOGLE_GENERATIVE_AI_MODELS\n build_config[\"model_name\"][\"value\"] = GOOGLE_GENERATIVE_AI_MODELS[0]\n build_config[\"api_key\"][\"display_name\"] = \"Google API Key\"\n return build_config\n" + }, + "input_value": { + "_input_type": "MessageInput", + "advanced": false, + "display_name": "Input", + "dynamic": false, + "info": "The input text to send to the model", + "input_types": [ + "Message" + ], + "list": false, + "list_add_label": "Add More", + "load_from_db": false, + "name": "input_value", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_input": true, + "trace_as_metadata": true, + "type": "str", + "value": "" + }, + "model_name": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Name", + "dynamic": false, + "info": "Select the model to use", + "name": "model_name", + "options": [ + "gpt-4o-mini", + "gpt-4o", + "gpt-4.1", + "gpt-4.1-mini", + "gpt-4.1-nano", + "gpt-4.5-preview", + "gpt-4-turbo", + "gpt-4-turbo-preview", + "gpt-4", + "gpt-3.5-turbo" + ], + "options_metadata": [], + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "gpt-4o-mini" + }, + "provider": { + "_input_type": "DropdownInput", + "advanced": false, + "combobox": false, + "dialog_inputs": {}, + "display_name": "Model Provider", + "dynamic": false, + "info": "Select the model provider", + "name": "provider", + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], + "options_metadata": [ + { + "icon": "OpenAI" + }, + { + "icon": "Anthropic" + }, + { + "icon": "GoogleGenerativeAI" + } + ], + "placeholder": "", + "real_time_refresh": true, + "required": false, + "show": true, + "title_case": false, + "toggle": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "str", + "value": "OpenAI" + }, + "stream": { + "_input_type": "BoolInput", + "advanced": true, + "display_name": "Stream", + "dynamic": false, + "info": "Whether to stream the response", + "list": false, + "list_add_label": "Add More", + "name": "stream", + "placeholder": "", + "required": false, + "show": true, + "title_case": false, + "tool_mode": false, + "trace_as_metadata": true, + "type": "bool", + "value": false + }, + "system_message": { + "_input_type": "MultilineInput", + "advanced": 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": "model_output", + "showNode": true, + "type": "LanguageModelComponent" + }, + "dragging": false, + "id": "LanguageModelComponent-dYtAT", + "measured": { + "height": 451, + "width": 320 + }, + "position": { + "x": 169.44463633485168, + "y": 5440.597009802169 + }, + "selected": false, + "type": "genericNode" } ], "viewport": { - "x": 442.6851065891309, - "y": -1378.1987686741775, - "zoom": 0.2815925120128663 + "x": 395.1563165134778, + "y": -2218.0028966370833, + "zoom": 0.43579829426169864 } }, "description": "The YouTube Analysis flow extracts video comments and transcripts, analyzing sentiment patterns and content themes.", "endpoint_name": null, - "id": "828f13a1-cb75-4c8f-90e7-6e948c2fd899", + "id": "7425d6b1-ab3d-4624-ada0-bf36654e4888", "is_component": false, - "last_tested_version": "1.4.2", + "last_tested_version": "1.4.3", "name": "Youtube Analysis", "tags": [ "agents", diff --git a/src/backend/tests/unit/components/agents/test_agent_component.py b/src/backend/tests/unit/components/agents/test_agent_component.py index a40b07237..e3ac1692f 100644 --- a/src/backend/tests/unit/components/agents/test_agent_component.py +++ b/src/backend/tests/unit/components/agents/test_agent_component.py @@ -14,7 +14,6 @@ from langflow.base.models.openai_constants import ( from langflow.components.agents.agent import AgentComponent from langflow.components.tools.calculator import CalculatorToolComponent from langflow.custom import Component -from langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI from tests.base import ComponentTestBaseWithClient, ComponentTestBaseWithoutClient from tests.unit.mock_language_model import MockLanguageModel @@ -50,9 +49,6 @@ class TestAgentComponent(ComponentTestBaseWithoutClient): "system_prompt": "You are a helpful assistant.", "tools": [], "verbose": True, - "session_id": str(uuid4()), - "sender": MESSAGE_SENDER_AI, - "sender_name": MESSAGE_SENDER_NAME_AI, } async def test_build_config_update(self, component_class, default_kwargs): @@ -129,7 +125,7 @@ class TestAgentComponentWithClient(ComponentTestBaseWithClient): input_value=input_value, api_key=api_key, model_name="gpt-4o", - llm_type="OpenAI", + agent_llm="OpenAI", temperature=temperature, _session_id=str(uuid4()), ) diff --git a/src/frontend/tests/core/integrations/Financial Agent.spec.ts b/src/frontend/tests/core/integrations/Financial Agent.spec.ts deleted file mode 100644 index dbcb33001..000000000 --- a/src/frontend/tests/core/integrations/Financial Agent.spec.ts +++ /dev/null @@ -1,78 +0,0 @@ -import { expect, test } from "@playwright/test"; -import * as dotenv from "dotenv"; -import path from "path"; -import { awaitBootstrapTest } from "../../utils/await-bootstrap-test"; -import { withEventDeliveryModes } from "../../utils/withEventDeliveryModes"; - -withEventDeliveryModes( - "Financial Agent", - { tag: ["@release", "@starter-projects"] }, - async ({ page }) => { - test.skip( - !process?.env?.TAVILY_API_KEY, - "TAVILY_API_KEY required to run this test", - ); - - test.skip( - !process?.env?.SAMBANOVA_API_KEY, - "SAMBANOVA_API_KEY required to run this test", - ); - - await page.goto("/"); - await awaitBootstrapTest(page); - - await page.getByTestId("side_nav_options_all-templates").click(); - await page.getByRole("heading", { name: "Financial Agent" }).click(); - - await page - .getByTestId("popover-anchor-input-api_key") - .nth(0) - .fill(process.env.TAVILY_API_KEY ?? ""); - - for (let i = 0; i < 2; i++) { - await page.getByTestId("dropdown_str_agent_llm").nth(i).click(); - await page.waitForTimeout(500); - await page.getByRole("option", { name: "SambaNova" }).click(); - } - - for (let i = 0; i < 3; i++) { - await page - .getByTestId("value-dropdown-dropdown_str_model_name") - .nth(i) - .click(); - await page.waitForTimeout(500); - - await page.getByRole("option").first().click(); - } - - for (let i = 1; i <= 3; i++) { - await page - .getByTestId("popover-anchor-input-api_key") - .nth(i) - .fill(process.env.SAMBANOVA_API_KEY ?? ""); - } - - await page.getByTestId("playground-btn-flow-io").click(); - - await page - .getByTestId("input-chat-playground") - .last() - .fill("Why did Nvidia stock drop in January?"); - - await page.getByTestId("button-send").last().click(); - - const stopButton = page.getByRole("button", { name: "Stop" }); - await stopButton.waitFor({ state: "visible", timeout: 30000 }); - - if (await stopButton.isVisible()) { - await expect(stopButton).toBeHidden({ timeout: 120000 }); - } - - const output = await page - .getByTestId("div-chat-message") - .last() - .innerText(); - expect(output.toLowerCase()).toContain("nvidia"); - expect(output.length).toBeGreaterThan(100); - }, -); diff --git a/src/frontend/tests/core/integrations/Market Research.spec.ts b/src/frontend/tests/core/integrations/Market Research.spec.ts index b3a0eb61e..0747d30e7 100644 --- a/src/frontend/tests/core/integrations/Market Research.spec.ts +++ b/src/frontend/tests/core/integrations/Market Research.spec.ts @@ -41,17 +41,6 @@ withEventDeliveryModes( .nth(0) .fill(process.env.TAVILY_API_KEY ?? ""); - //* TODO: Remove these 5 steps once the template is updated *// - await page.getByTestId("dropdown-output-openaimodel").click(); - - await page - .getByTestId("dropdown-item-output-openaimodel-language model") - .click(); - - await page - .getByTestId("handle-structuredoutput-shownode-structured output-right") - .click(); - await page .getByTestId("handle-parser-shownode-data or dataframe-left") .click();