diff --git a/.github/workflows/python_test.yml b/.github/workflows/python_test.yml index 1c3039a54af9..b6043d95a8d1 100644 --- a/.github/workflows/python_test.yml +++ b/.github/workflows/python_test.yml @@ -32,8 +32,6 @@ jobs: python-version: ${{ fromJson(inputs.python-versions || '["3.10", "3.11", "3.12"]' ) }} splitCount: [5] group: [1, 2, 3, 4, 5] - env: - OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} steps: - uses: actions/checkout@v4 with: @@ -59,6 +57,33 @@ jobs: timeout_minutes: 12 max_attempts: 2 command: make unit_tests async=false args="--splits ${{ matrix.splitCount }} --group ${{ matrix.group }}" + integration-tests: + name: Integration Tests - Python ${{ matrix.python-version }} + runs-on: ubuntu-latest + strategy: + matrix: + python-version: ${{ fromJson(inputs.python-versions || '["3.10", "3.11", "3.12"]' ) }} + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.branch || github.ref }} + - name: Setup Node.js + uses: actions/setup-node@v4 + id: setup-node + with: + node-version: ${{ env.NODE_VERSION }} + - name: Set up Python ${{ matrix.python-version }} + Poetry ${{ env.POETRY_VERSION }} + uses: "./.github/actions/poetry_caching" + with: + python-version: ${{ matrix.python-version }} + poetry-version: ${{ env.POETRY_VERSION }} + cache-key: ${{ runner.os }}-poetry-${{ env.POETRY_VERSION }}-${{ hashFiles('**/poetry.lock') }} + - name: Install Python dependencies + run: | + poetry env use ${{ matrix.python-version }} + poetry install + - name: Run integration tests + run: make integration_tests test-cli: name: Test CLI - Python ${{ matrix.python-version }} diff --git a/.github/workflows/scheduled_integration_test.yml b/.github/workflows/scheduled_integration_test.yml index 56afc035f2ea..23115684cdb1 100644 --- a/.github/workflows/scheduled_integration_test.yml +++ b/.github/workflows/scheduled_integration_test.yml @@ -43,7 +43,12 @@ jobs: run: | poetry env use ${{ matrix.python-version }} poetry install - - name: Run integration tests + - name: Run unit tests with api keys timeout-minutes: 12 run: | - make integration_tests + make unit_tests_api_keys + + - name: Run integration tests with api keys + timeout-minutes: 20 + run: | + make integration_tests_api_keys diff --git a/Makefile b/Makefile index 6afc72791cc4..7139ce8d7c10 100644 --- a/Makefile +++ b/Makefile @@ -148,9 +148,20 @@ else $(args) endif +unit_tests_api_keys: ## run unit tests only with api key tests + poetry run pytest src/backend/tests \ + --ignore=src/backend/tests/integration \ + --instafail -n auto -ra -m "api_key_required" \ + $(args) + integration_tests: ## run integration tests poetry run pytest src/backend/tests/integration \ - --instafail -ra \ + --instafail -ra -m "not api_key_required" \ + $(args) + +integration_tests_api_keys: ## run integration tests only with api key tests + poetry run pytest src/backend/tests/integration \ + --instafail -ra -m "api_key_required" \ $(args) tests: ## run unit, integration, coverage tests diff --git a/pyproject.toml b/pyproject.toml index 9ca874113f94..b650accddb8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -105,6 +105,7 @@ wolframalpha = "^5.1.3" astra-assistants = "^2.1.0.10" composio-langchain = "^0.5.8" spider-client = "^0.0.27" +pytest = "^8.3.2" [tool.poetry.group.dev.dependencies] diff --git a/src/backend/base/langflow/components/inputs/ChatInput.py b/src/backend/base/langflow/components/inputs/ChatInput.py index 28aa220a0f2e..f4c80054201d 100644 --- a/src/backend/base/langflow/components/inputs/ChatInput.py +++ b/src/backend/base/langflow/components/inputs/ChatInput.py @@ -62,6 +62,7 @@ class ChatInput(ChatComponent): ] def message_response(self) -> Message: + print("running", self.input_value) message = Message( text=self.input_value, sender=self.sender, diff --git a/src/backend/base/langflow/components/prompts/Prompt.py b/src/backend/base/langflow/components/prompts/Prompt.py index 512398b0d38d..9e36a52de48d 100644 --- a/src/backend/base/langflow/components/prompts/Prompt.py +++ b/src/backend/base/langflow/components/prompts/Prompt.py @@ -24,8 +24,10 @@ class PromptComponent(Component): async def build_prompt( self, ) -> Message: + print("build_prompt") prompt = await Message.from_template_and_variables(**self._attributes) self.status = prompt.text + return prompt def _update_template(self, frontend_node: dict): @@ -41,6 +43,9 @@ def _update_template(self, frontend_node: dict): return frontend_node def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict): + print("post code..") + import traceback + traceback.print_stack() """ This function is called after the code validation is done. """ diff --git a/src/backend/base/langflow/custom/custom_component/component.py b/src/backend/base/langflow/custom/custom_component/component.py index da14c673c627..7f832763f7bb 100644 --- a/src/backend/base/langflow/custom/custom_component/component.py +++ b/src/backend/base/langflow/custom/custom_component/component.py @@ -263,7 +263,7 @@ def map_inputs(self, inputs: list["InputTypes"]): for input_ in inputs: if input_.name is None: raise ValueError("Input name cannot be None.") - self._inputs[input_.name] = input_ + self._inputs[input_.name] = deepcopy(input_) def validate(self, params: dict): """ @@ -473,6 +473,8 @@ def _map_parameters_on_template(self, template: dict): for name, value in self._parameters.items(): try: template[name]["value"] = value + if value and "load_from_db" in template[name]: + template[name]["load_from_db"] = False except KeyError: close_match = find_closest_match(name, list(template.keys())) if close_match: diff --git a/src/backend/base/langflow/graph/graph/base.py b/src/backend/base/langflow/graph/graph/base.py index e29f6c1d57c5..e2c5a6a24b63 100644 --- a/src/backend/base/langflow/graph/graph/base.py +++ b/src/backend/base/langflow/graph/graph/base.py @@ -26,6 +26,7 @@ from langflow.graph.vertex.base import Vertex, VertexStates from langflow.graph.vertex.schema import NodeData from langflow.graph.vertex.types import ComponentVertex, InterfaceVertex, StateVertex +from langflow.interface import initialize from langflow.logging.logger import LogConfig, configure from langflow.schema import Data from langflow.schema.schema import INPUT_FIELD_NAME, InputType @@ -195,33 +196,30 @@ def add_nodes_and_edges(self, nodes: list[NodeData], edges: list[EdgeData]): self._edges = self._graph_data["edges"] self.initialize() - def add_component(self, _id: str, component: "Component"): - if _id in self.vertex_map: - return + + async def add_component(self, component: "Component", component_id: Optional[str] = None) -> str: + component_id = component_id or str(component.name + "-" + str(uuid.uuid4())) + if component_id in self.vertex_map: + raise ValueError(f"Component ID {component_id} already exists") + if not component_id.startswith(component.name): + raise ValueError(f"Component ID {component_id} does not match component name {component.name}") frontend_node = component.to_frontend_node() - frontend_node["data"]["id"] = _id - frontend_node["id"] = _id + frontend_node["data"]["id"] = component_id + frontend_node["id"] = component_id self._vertices.append(frontend_node) vertex = self._create_vertex(frontend_node) vertex.add_component_instance(component) self.vertices.append(vertex) - self.vertex_map[_id] = vertex - - if component._edges: - for edge in component._edges: - self._add_edge(edge) - - if component._components: - for _component in component._components: - self.add_component(_component._id, _component) + self.vertex_map[component_id] = vertex + return component_id def _set_start_and_end(self, start: "Component", end: "Component"): if not hasattr(start, "to_frontend_node"): raise TypeError(f"start must be a Component. Got {type(start)}") if not hasattr(end, "to_frontend_node"): raise TypeError(f"end must be a Component. Got {type(end)}") - self.add_component(start._id, start) - self.add_component(end._id, end) + self.add_component(start, start._id) + self.add_component(end, end._id) def add_component_edge(self, source_id: str, output_input_tuple: tuple[str, str], target_id: str): source_vertex = self.get_vertex(source_id) @@ -235,6 +233,20 @@ def add_component_edge(self, source_id: str, output_input_tuple: tuple[str, str] raise ValueError(f"Source vertex {source_id} does not have a custom component.") if target_vertex._custom_component is None: raise ValueError(f"Target vertex {target_id} does not have a custom component.") + + try: + input_field = target_vertex.get_input(input_name) + input_types = input_field.input_types + input_field_type = str(input_field.field_type) + except ValueError: + input_field = target_vertex.data.get("node", {}).get("template", {}).get(input_name) + if not input_field: + raise ValueError(f"Input field {input_name} not found in target vertex {target_id}") + input_types = input_field.get("input_types", []) + input_field_type = input_field.get("type", "") + + + edge_data: EdgeData = { "source": source_id, "target": target_id, @@ -249,8 +261,8 @@ def add_component_edge(self, source_id: str, output_input_tuple: tuple[str, str] "targetHandle": { "fieldName": input_name, "id": target_vertex.id, - "inputTypes": target_vertex.get_input(input_name).input_types, - "type": str(target_vertex.get_input(input_name).field_type), + "inputTypes": input_types, + "type": input_field_type, }, }, } diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json index c79bdb1070d1..a6289948296b 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting (Hello, World).json @@ -141,7 +141,7 @@ "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 import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n print(\"running\", self.input_value)\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" }, "files": { "advanced": true, @@ -356,7 +356,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n" }, "template": { "advanced": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json index 24651b62089c..f3592de0491f 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json @@ -425,7 +425,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" }, "instructions": { "advanced": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json index f946f5b8ac48..2b20ef1a34db 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Complex Agent.json @@ -2329,7 +2329,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" }, "query": { "advanced": false, @@ -2442,7 +2442,7 @@ "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 import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n print(\"running\", self.input_value)\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" }, "files": { "advanced": true, @@ -3896,7 +3896,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" }, "goal": { "advanced": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json b/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json index 5a8fe5dabb0a..5884b6fd745d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Document QA.json @@ -242,7 +242,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n" }, "template": { "advanced": false, @@ -338,7 +338,7 @@ "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 import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n print(\"running\", self.input_value)\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" }, "files": { "advanced": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json index ce0a3442a364..59be786a0e4a 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Hierarchical Agent.json @@ -2053,7 +2053,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" }, "query": { "advanced": false, @@ -2170,7 +2170,7 @@ "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 import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n print(\"running\", self.input_value)\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" }, "files": { "advanced": true, 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 089b84c536ea..add43972e409 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 @@ -168,7 +168,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" }, "context": { "advanced": false, @@ -312,7 +312,7 @@ "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 import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n print(\"running\", self.input_value)\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" }, "files": { "advanced": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json index 258af3ae731b..ecdea9a9b00b 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Agent.json @@ -1194,7 +1194,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n" }, "template": { "advanced": false, @@ -1314,7 +1314,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n" }, "template": { "advanced": false, @@ -1434,7 +1434,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(new_frontend_node, current_frontend_node)\n template = frontend_node[\"template\"][\"template\"][\"value\"]\n # Kept it duplicated for backwards compatibility\n _ = process_prompt_template(\n template=template,\n name=\"template\",\n custom_fields=frontend_node[\"custom_fields\"],\n frontend_node_template=frontend_node[\"template\"],\n )\n # Now that template is updated, we need to grab any values that were set in the current_frontend_node\n # and update the frontend_node with those values\n update_template_values(new_template=frontend_node, previous_template=current_frontend_node[\"template\"])\n return frontend_node\n\n def _get_fallback_input(self, **kwargs):\n return DefaultPromptField(**kwargs)\n" }, "template": { "advanced": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json index c62b2492c7cb..9b40ef5e6f1d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json @@ -326,7 +326,7 @@ "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 import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" + "value": "from langflow.base.data.utils import IMG_FILE_TYPES, TEXT_FILE_TYPES\nfrom langflow.base.io.chat import ChatComponent\nfrom langflow.inputs import BoolInput\nfrom langflow.io import DropdownInput, FileInput, MessageTextInput, MultilineInput, Output\nfrom langflow.memory import store_message\nfrom langflow.schema.message import Message\nfrom langflow.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_USER, MESSAGE_SENDER_NAME_USER\n\n\nclass ChatInput(ChatComponent):\n display_name = \"Chat Input\"\n description = \"Get chat inputs from the Playground.\"\n icon = \"ChatInput\"\n name = \"ChatInput\"\n\n inputs = [\n MultilineInput(\n name=\"input_value\",\n display_name=\"Text\",\n value=\"\",\n info=\"Message to be passed as input.\",\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 ),\n ]\n outputs = [\n Output(display_name=\"Message\", name=\"message\", method=\"message_response\"),\n ]\n\n def message_response(self) -> Message:\n print(\"running\", self.input_value)\n message = Message(\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 )\n\n if (\n self.session_id\n and isinstance(message, Message)\n and isinstance(message.text, str)\n and self.should_store_message\n ):\n store_message(\n message,\n flow_id=self.graph.flow_id,\n )\n self.message.value = message\n\n self.status = message\n return message\n" }, "files": { "advanced": true, @@ -1145,7 +1145,7 @@ "show": true, "title_case": false, "type": "code", - "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n prompt = await Message.from_template_and_variables(**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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" + "value": "from langflow.base.prompts.api_utils import process_prompt_template\nfrom langflow.custom import Component\nfrom langflow.inputs.inputs import DefaultPromptField\nfrom langflow.io import 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 = \"prompts\"\n trace_type = \"prompt\"\n name = \"Prompt\"\n\n inputs = [\n PromptInput(name=\"template\", display_name=\"Template\"),\n ]\n\n outputs = [\n Output(display_name=\"Prompt Message\", name=\"prompt\", method=\"build_prompt\"),\n ]\n\n async def build_prompt(\n self,\n ) -> Message:\n print(\"build_prompt\")\n prompt = await Message.from_template_and_variables(**self._attributes)\n self.status = prompt.text\n\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 def post_code_processing(self, new_frontend_node: dict, current_frontend_node: dict):\n print(\"post code..\")\n import traceback\n traceback.print_stack()\n \"\"\"\n This function is called after the code validation is done.\n \"\"\"\n frontend_node = super().post_code_processing(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" }, "context": { "advanced": false, diff --git a/src/backend/tests/integration/astra/__init__.py b/src/backend/tests/__init__.py similarity index 100% rename from src/backend/tests/integration/astra/__init__.py rename to src/backend/tests/__init__.py diff --git a/src/backend/tests/api_keys.py b/src/backend/tests/api_keys.py new file mode 100644 index 000000000000..1566c1a8efb8 --- /dev/null +++ b/src/backend/tests/api_keys.py @@ -0,0 +1,55 @@ +import json +import os.path +import shutil + +# we need to import tmpdir +import tempfile +from contextlib import contextmanager, suppress +from pathlib import Path +from typing import TYPE_CHECKING, AsyncGenerator + +import orjson +import pytest +from dotenv import load_dotenv +from fastapi.testclient import TestClient +from httpx import AsyncClient +from sqlmodel import Session, SQLModel, create_engine, select +from sqlmodel.pool import StaticPool +from typer.testing import CliRunner + +from langflow.graph.graph.base import Graph +from langflow.initial_setup.setup import STARTER_FOLDER_NAME +from langflow.services.auth.utils import get_password_hash +from langflow.services.database.models.api_key.model import ApiKey +from langflow.services.database.models.flow.model import Flow, FlowCreate +from langflow.services.database.models.folder.model import Folder +from langflow.services.database.models.user.model import User, UserCreate +from langflow.services.database.utils import session_getter +from langflow.services.deps import get_db_service + +def get_required_env_var(var: str) -> str: + """ + Get the value of the specified environment variable. + + Args: + var (str): The environment variable to get. + + Returns: + str: The value of the environment variable. + + Raises: + ValueError: If the environment variable is not set. + """ + value = os.getenv(var) + if not value: + raise ValueError(f"Environment variable {var} is not set") + return value + +def get_openai_api_key() -> str: + return get_required_env_var("OPENAI_API_KEY") + +def get_astradb_application_token() -> str: + return get_required_env_var("ASTRA_DB_APPLICATION_TOKEN") + +def get_astradb_api_endpoint() -> str: + return get_required_env_var("ASTRA_DB_API_ENDPOINT") diff --git a/src/backend/tests/conftest.py b/src/backend/tests/conftest.py index 600f32cacdd7..00cfc2de61ef 100644 --- a/src/backend/tests/conftest.py +++ b/src/backend/tests/conftest.py @@ -27,6 +27,7 @@ from langflow.services.database.models.user.model import User, UserCreate from langflow.services.database.utils import session_getter from langflow.services.deps import get_db_service +from tests.api_keys import get_openai_api_key if TYPE_CHECKING: from langflow.services.database.service import DatabaseService @@ -463,6 +464,9 @@ def get_starter_project(active_user): if not flow: raise ValueError("No starter project found") + + # ensure openai api key is set + get_openai_api_key() new_flow_create = FlowCreate( name=flow.name, description=flow.description, diff --git a/src/backend/tests/integration/backward_compatibility/test_starter_projects.py b/src/backend/tests/integration/backward_compatibility/test_starter_projects.py new file mode 100644 index 000000000000..d6e815b9e0a7 --- /dev/null +++ b/src/backend/tests/integration/backward_compatibility/test_starter_projects.py @@ -0,0 +1,17 @@ +import json + +import pytest +from langflow.schema.message import Message +from tests.api_keys import get_openai_api_key +from tests.integration.utils import run_flow, download_flow_from_github, run_json_flow + + +@pytest.mark.asyncio +@pytest.mark.api_key_required +async def test_1_0_15_basic_prompting(): + api_key = get_openai_api_key() + json_flow = download_flow_from_github("Basic Prompting (Hello, World)", "1.0.15") + json_flow.set_value(json_flow.get_component_by_type("OpenAIModel"), "api_key", api_key) + outputs = await run_json_flow(json_flow, run_input="hello!") + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "This is the message: hello!" diff --git a/src/backend/tests/integration/components/astra/__init__.py b/src/backend/tests/integration/components/astra/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/backend/tests/integration/astra/test_astra_component.py b/src/backend/tests/integration/components/astra/test_astra_component.py similarity index 68% rename from src/backend/tests/integration/astra/test_astra_component.py rename to src/backend/tests/integration/components/astra/test_astra_component.py index 2742b0e3bd2c..2367d4662c1e 100644 --- a/src/backend/tests/integration/astra/test_astra_component.py +++ b/src/backend/tests/integration/components/astra/test_astra_component.py @@ -1,13 +1,17 @@ import os import pytest -from integration.utils import MockEmbeddings, check_env_vars, valid_nvidia_vectorize_region + +from tests.api_keys import get_astradb_application_token, get_astradb_api_endpoint +from tests.integration.utils import MockEmbeddings, check_env_vars, valid_nvidia_vectorize_region from langchain_core.documents import Document # from langflow.components.memories.AstraDBMessageReader import AstraDBMessageReaderComponent # from langflow.components.memories.AstraDBMessageWriter import AstraDBMessageWriterComponent from langflow.components.vectorstores.AstraDB import AstraVectorStoreComponent +from langflow.graph import Graph from langflow.schema.data import Data +from tests.integration.utils import run_single_component COLLECTION = "test_basic" SEARCH_COLLECTION = "test_search" @@ -17,58 +21,25 @@ VECTORIZE_COLLECTION_OPENAI_WITH_AUTH = "test_vectorize_openai_auth" -@pytest.fixture() -def astra_fixture(request): - """ - Sets up the astra collection and cleans up after - """ - try: - from langchain_astradb import AstraDBVectorStore - except ImportError: - raise ImportError( - "Could not import langchain Astra DB integration package. Please install it with `pip install langchain-astradb`." - ) - - store = AstraDBVectorStore( - collection_name=request.param, - embedding=MockEmbeddings(), - api_endpoint=os.getenv("ASTRA_DB_API_ENDPOINT"), - token=os.getenv("ASTRA_DB_APPLICATION_TOKEN"), - ) - - yield - store.delete_collection() - - -@pytest.mark.skipif( - not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT"), - reason="missing astra env vars", -) -@pytest.mark.parametrize("astra_fixture", [COLLECTION], indirect=True) -def test_astra_setup(astra_fixture): - application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN") - api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT") +@pytest.mark.api_key_required +@pytest.mark.asyncio +async def test_astra_setup(): + application_token = get_astradb_application_token() + api_endpoint = get_astradb_api_endpoint() embedding = MockEmbeddings() - - component = AstraVectorStoreComponent() - component.build( - token=application_token, - api_endpoint=api_endpoint, - collection_name=COLLECTION, - embedding=embedding, - ) - component.build_vector_store() - - -@pytest.mark.skipif( - not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT"), - reason="missing astra env vars", -) -@pytest.mark.parametrize("astra_fixture", [SEARCH_COLLECTION], indirect=True) -def test_astra_embeds_and_search(astra_fixture): - application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN") - api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT") + results = await run_single_component(AstraVectorStoreComponent, inputs={ + "token": application_token, + "api_endpoint": api_endpoint, + "collection_name": COLLECTION, + "embedding": embedding, + }) + print(results) + +@pytest.mark.api_key_required +def test_astra_embeds_and_search(): + application_token = get_astradb_application_token() + api_endpoint = get_astradb_api_endpoint() embedding = MockEmbeddings() documents = [Document(page_content="test1"), Document(page_content="test2")] @@ -90,28 +61,25 @@ def test_astra_embeds_and_search(astra_fixture): assert len(records) == 1 -@pytest.mark.skipif( - not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT") - or not valid_nvidia_vectorize_region(os.getenv("ASTRA_DB_API_ENDPOINT")), - reason="missing env vars or invalid region for nvidia vectorize", -) + +@pytest.mark.api_key_required def test_astra_vectorize(): from langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions from langflow.components.embeddings.AstraVectorize import AstraVectorizeComponent + application_token = get_astradb_application_token() + api_endpoint = get_astradb_api_endpoint() store = None try: options = {"provider": "nvidia", "modelName": "NV-Embed-QA"} store = AstraDBVectorStore( collection_name=VECTORIZE_COLLECTION, - api_endpoint=os.getenv("ASTRA_DB_API_ENDPOINT"), - token=os.getenv("ASTRA_DB_APPLICATION_TOKEN"), + api_endpoint=api_endpoint, + token=application_token, collection_vector_service_options=CollectionVectorServiceOptions.from_dict(options), ) - application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN") - api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT") documents = [Document(page_content="test1"), Document(page_content="test2")] records = [Data.from_document(d) for d in documents] @@ -139,20 +107,18 @@ def test_astra_vectorize(): store.delete_collection() -@pytest.mark.skipif( - not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT", "OPENAI_API_KEY"), - reason="missing env vars", -) +@pytest.mark.api_key_required def test_astra_vectorize_with_provider_api_key(): """tests vectorize using an openai api key""" from langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions from langflow.components.embeddings.AstraVectorize import AstraVectorizeComponent + application_token = get_astradb_application_token() + api_endpoint = get_astradb_api_endpoint() + store = None try: - application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN") - api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT") options = {"provider": "openai", "modelName": "text-embedding-3-small", "parameters": {}, "authentication": {}} store = AstraDBVectorStore( collection_name=VECTORIZE_COLLECTION_OPENAI, @@ -188,10 +154,7 @@ def test_astra_vectorize_with_provider_api_key(): store.delete_collection() -@pytest.mark.skipif( - not check_env_vars("ASTRA_DB_APPLICATION_TOKEN", "ASTRA_DB_API_ENDPOINT"), - reason="missing env vars", -) +@pytest.mark.api_key_required def test_astra_vectorize_passes_authentication(): """tests vectorize using the authentication parameter""" from langchain_astradb import AstraDBVectorStore, CollectionVectorServiceOptions @@ -200,8 +163,8 @@ def test_astra_vectorize_passes_authentication(): store = None try: - application_token = os.getenv("ASTRA_DB_APPLICATION_TOKEN") - api_endpoint = os.getenv("ASTRA_DB_API_ENDPOINT") + application_token = get_astradb_application_token() + api_endpoint = get_astradb_api_endpoint() options = { "provider": "openai", "modelName": "text-embedding-3-small", diff --git a/src/backend/tests/integration/components/inputs/__init__.py b/src/backend/tests/integration/components/inputs/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/backend/tests/integration/components/inputs/test_chat_input.py b/src/backend/tests/integration/components/inputs/test_chat_input.py new file mode 100644 index 000000000000..de2f48e0cefa --- /dev/null +++ b/src/backend/tests/integration/components/inputs/test_chat_input.py @@ -0,0 +1,55 @@ +from langflow.memory import get_messages +from langflow.schema.message import Message +from tests.integration.utils import run_single_component + +from langflow.components.inputs import ChatInput +import pytest + + +@pytest.mark.asyncio +async def test_default(): + outputs = await run_single_component(ChatInput, run_input="hello") + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + assert outputs["message"].sender == "User" + assert outputs["message"].sender_name == "User" + + outputs = await run_single_component(ChatInput, run_input="") + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "" + assert outputs["message"].sender == "User" + assert outputs["message"].sender_name == "User" + +@pytest.mark.asyncio +async def test_sender(): + outputs = await run_single_component(ChatInput, inputs={ + "sender": "Machine", + "sender_name": "AI" + }, run_input="hello") + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + assert outputs["message"].sender == "Machine" + assert outputs["message"].sender_name == "AI" + + +@pytest.mark.asyncio +async def test_do_not_store_messages(): + session_id = "test-session-id" + outputs = await run_single_component(ChatInput, inputs={ + "should_store_message": True + }, run_input="hello", session_id=session_id) + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + assert outputs["message"].session_id == session_id + + assert len(get_messages(session_id=session_id)) == 1 + + session_id = "test-session-id-another" + outputs = await run_single_component(ChatInput, inputs={ + "should_store_message": False + }, run_input="hello", session_id=session_id) + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + assert outputs["message"].session_id == session_id + + assert len(get_messages(session_id=session_id)) == 0 diff --git a/src/backend/tests/integration/components/outputs/__init__.py b/src/backend/tests/integration/components/outputs/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/backend/tests/integration/components/outputs/test_chat_output.py b/src/backend/tests/integration/components/outputs/test_chat_output.py new file mode 100644 index 000000000000..8e0e2bb553f7 --- /dev/null +++ b/src/backend/tests/integration/components/outputs/test_chat_output.py @@ -0,0 +1,52 @@ +from langflow.components.outputs import ChatOutput +from langflow.memory import get_messages +from langflow.schema.message import Message +from tests.integration.utils import run_single_component + +from langflow.components.inputs import ChatInput +import pytest + + +@pytest.mark.asyncio +async def test_string(): + outputs = await run_single_component(ChatOutput, inputs={ + "input_value": "hello" + }) + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + assert outputs["message"].sender == "Machine" + assert outputs["message"].sender_name == "AI" + + +@pytest.mark.asyncio +async def test_message(): + outputs = await run_single_component(ChatOutput, inputs={ + "input_value": Message(text="hello") + }) + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + assert outputs["message"].sender == "Machine" + assert outputs["message"].sender_name == "AI" + + +@pytest.mark.asyncio +async def test_do_not_store_message(): + session_id = "test-session-id" + outputs = await run_single_component(ChatOutput, inputs={ + "input_value": "hello", + "should_store_message": True + }, session_id=session_id) + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + + assert len(get_messages(session_id=session_id)) == 1 + session_id = "test-session-id-another" + + outputs = await run_single_component(ChatOutput, inputs={ + "input_value": "hello", + "should_store_message": False + }, session_id=session_id) + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "hello" + + assert len(get_messages(session_id=session_id)) == 0 diff --git a/src/backend/tests/integration/components/prompts/__init__.py b/src/backend/tests/integration/components/prompts/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/src/backend/tests/integration/components/prompts/test_prompt.py b/src/backend/tests/integration/components/prompts/test_prompt.py new file mode 100644 index 000000000000..09a42246a5d4 --- /dev/null +++ b/src/backend/tests/integration/components/prompts/test_prompt.py @@ -0,0 +1,19 @@ +from langflow.components.outputs import ChatOutput +from langflow.components.prompts import Prompt, PromptComponent +from langflow.memory import get_messages +from langflow.schema.message import Message +from tests.integration.utils import run_single_component + +from langflow.components.inputs import ChatInput +import pytest + + +@pytest.mark.asyncio +async def test(): + outputs = await run_single_component(PromptComponent, inputs={ + "template": "test {var1}", + "var1": "from the var" + }) + print(outputs) + assert isinstance(outputs["prompt"], Message) + assert outputs["prompt"].text == "test from the var" diff --git a/src/backend/tests/integration/flows/test_basic_prompting.py b/src/backend/tests/integration/flows/test_basic_prompting.py new file mode 100644 index 000000000000..ab5dfc184ca1 --- /dev/null +++ b/src/backend/tests/integration/flows/test_basic_prompting.py @@ -0,0 +1,22 @@ +import pytest + +from langflow.components.inputs import ChatInput +from langflow.components.outputs import ChatOutput +from langflow.components.prompts import PromptComponent +from langflow.graph import Graph +from langflow.schema.message import Message +from tests.integration.utils import run_flow + + +@pytest.mark.asyncio +async def test_simple_no_llm(): + graph = Graph() + input = await graph.add_component(ChatInput()) + output = await graph.add_component(ChatOutput()) + component = PromptComponent(template="This is the message: {var1}", var1="") + prompt = await graph.add_component(component) + graph.add_component_edge(input, ("message", "var1"), prompt) + graph.add_component_edge(prompt, ("prompt", "input_value"), output) + outputs = await run_flow(graph, run_input="hello!") + assert isinstance(outputs["message"], Message) + assert outputs["message"].text == "This is the message: hello!" diff --git a/src/backend/tests/integration/langflow.py b/src/backend/tests/integration/test_misc.py similarity index 100% rename from src/backend/tests/integration/langflow.py rename to src/backend/tests/integration/test_misc.py diff --git a/src/backend/tests/integration/utils.py b/src/backend/tests/integration/utils.py index 1e79ee1db64f..3af4f6eb5c3c 100644 --- a/src/backend/tests/integration/utils.py +++ b/src/backend/tests/integration/utils.py @@ -1,7 +1,16 @@ +import dataclasses import os +import uuid +from typing import Optional, Any from astrapy.admin import parse_api_endpoint + +from langflow.api.v1.schemas import InputValueRequest from langflow.field_typing import Embeddings +from langflow.graph import Graph +from langflow.processing.process import run_graph_internal +import requests + def check_env_vars(*vars): @@ -49,3 +58,89 @@ def embed_documents(self, texts: list[str]) -> list[list[float]]: def embed_query(self, text: str) -> list[float]: self.embedded_query = text return self.mock_embedding(text) + +@dataclasses.dataclass +class JSONFlow: + json: dict + + def get_components_by_type(self, component_type): + result = [] + for node in self.json["data"]["nodes"]: + if node["data"]["type"] == component_type: + result.append(node["id"]) + if not result: + raise ValueError( + f"Component of type {component_type} not found, available types: {', '.join(set(node['data']['type'] for node in self.json['data']['nodes']))}") + return result + + def get_component_by_type(self, component_type): + components = self.get_components_by_type(component_type) + if len(components) > 1: + raise ValueError(f"Multiple components of type {component_type} found") + return components[0] + + def set_value(self, component_id, key, value): + done = False + for node in self.json["data"]["nodes"]: + if node["id"] == component_id: + if key not in node["data"]["node"]["template"]: + raise ValueError(f"Component {component_id} does not have input {key}") + node["data"]["node"]["template"][key]["value"] = value + node["data"]["node"]["template"][key]["load_from_db"] = False + done = True + break + if not done: + raise ValueError(f"Component {component_id} not found") + + +def download_flow_from_github(name: str, version: str) -> JSONFlow: + response = requests.get( + f"https://raw.githubusercontent.com/langflow-ai/langflow/v{version}/src/backend/base/langflow/initial_setup/starter_projects/{name}.json") + response.raise_for_status() + as_json = response.json() + return JSONFlow(json=as_json) + + +async def run_json_flow(json_flow: JSONFlow, run_input: Optional[Any] = None, + session_id: Optional[str] = None) -> dict[str, Any]: + graph = Graph.from_payload(json_flow.json) + return await run_flow(graph, run_input, session_id) + +async def run_flow(graph: Graph, run_input: Optional[Any] = None, + session_id: Optional[str] = None) -> dict[str, Any]: + graph.prepare() + if run_input: + graph_run_inputs = [InputValueRequest(input_value=run_input, type="chat")] + else: + graph_run_inputs = [] + + flow_id = str(uuid.uuid4()) + + results, _ = await run_graph_internal(graph, flow_id, session_id=session_id, + inputs=graph_run_inputs) + outputs = {} + for r in results: + for out in r.outputs: + outputs |= out.results + return outputs + + +async def run_single_component(clazz: type, inputs: dict = None, run_input: Optional[Any] = None, + session_id: Optional[str] = None) -> dict[str, Any]: + component = clazz( + **(inputs or {}) + ) + + flow_id = str(uuid.uuid4()) + graph = Graph(user_id=str(uuid.uuid4()), flow_id=flow_id) + component_id = await graph.add_component(component) + graph.prepare() + if run_input: + graph_run_inputs = [InputValueRequest(input_value=run_input, type="chat")] + else: + graph_run_inputs = [] + + _, _ = await run_graph_internal(graph, flow_id, session_id=session_id, + inputs=graph_run_inputs, + outputs=[component_id]) + return graph.get_vertex(component_id)._built_object diff --git a/src/backend/tests/unit/components/models/test_ChatOllama_component.py b/src/backend/tests/unit/components/models/test_ChatOllama_component.py deleted file mode 100644 index abd0d0c9485e..000000000000 --- a/src/backend/tests/unit/components/models/test_ChatOllama_component.py +++ /dev/null @@ -1,125 +0,0 @@ -import pytest -from unittest.mock import patch, MagicMock -from langflow.components.models.OllamaModel import ChatOllamaComponent -from langchain_community.chat_models.ollama import ChatOllama -from urllib.parse import urljoin - - -@pytest.fixture -def component(): - return ChatOllamaComponent() - - -@patch("httpx.Client.get") -def test_get_model_success(mock_get, component): - mock_response = MagicMock() - mock_response.json.return_value = {"models": [{"name": "model1"}, {"name": "model2"}]} - mock_response.raise_for_status.return_value = None - mock_get.return_value = mock_response - - base_url = "http://localhost:11434" - - model_names = component.get_model(base_url) - - expected_url = urljoin(base_url, "/api/tags") - - mock_get.assert_called_once_with(expected_url) - - assert model_names == ["model1", "model2"] - - -@patch("httpx.Client.get") -def test_get_model_failure(mock_get, component): - # Mock the response for the HTTP GET request to raise an exception - mock_get.side_effect = Exception("HTTP request failed") - - url = "http://localhost:11434/api/tags" - - # Assert that the ValueError is raised when an exception occurs - with pytest.raises(ValueError, match="Could not retrieve models"): - component.get_model(url) - - -def test_update_build_config_mirostat_disabled(component): - build_config = { - "mirostat_eta": {"advanced": False, "value": 0.1}, - "mirostat_tau": {"advanced": False, "value": 5}, - } - field_value = "Disabled" - field_name = "mirostat" - - updated_config = component.update_build_config(build_config, field_value, field_name) - - assert updated_config["mirostat_eta"]["advanced"] is True - assert updated_config["mirostat_tau"]["advanced"] is True - assert updated_config["mirostat_eta"]["value"] is None - assert updated_config["mirostat_tau"]["value"] is None - - -def test_update_build_config_mirostat_enabled(component): - build_config = { - "mirostat_eta": {"advanced": False, "value": None}, - "mirostat_tau": {"advanced": False, "value": None}, - } - field_value = "Mirostat 2.0" - field_name = "mirostat" - - updated_config = component.update_build_config(build_config, field_value, field_name) - - assert updated_config["mirostat_eta"]["advanced"] is False - assert updated_config["mirostat_tau"]["advanced"] is False - assert updated_config["mirostat_eta"]["value"] == 0.2 - assert updated_config["mirostat_tau"]["value"] == 10 - - -@patch("httpx.Client.get") -def test_update_build_config_model_name(mock_get, component): - # Mock the response for the HTTP GET request - mock_response = MagicMock() - mock_response.json.return_value = {"models": [{"name": "model1"}, {"name": "model2"}]} - mock_response.raise_for_status.return_value = None - mock_get.return_value = mock_response - - build_config = { - "base_url": {"load_from_db": False, "value": None}, - "model_name": {"options": []}, - } - field_value = None - field_name = "model_name" - - updated_config = component.update_build_config(build_config, field_value, field_name) - - assert updated_config["model_name"]["options"] == ["model1", "model2"] - - -def test_update_build_config_keep_alive(component): - build_config = {"keep_alive": {"value": None, "advanced": False}} - field_value = "Keep" - field_name = "keep_alive_flag" - - updated_config = component.update_build_config(build_config, field_value, field_name) - assert updated_config["keep_alive"]["value"] == "-1" - assert updated_config["keep_alive"]["advanced"] is True - - field_value = "Immediately" - updated_config = component.update_build_config(build_config, field_value, field_name) - assert updated_config["keep_alive"]["value"] == "0" - assert updated_config["keep_alive"]["advanced"] is True - - -@patch( - "langchain_community.chat_models.ChatOllama", - return_value=ChatOllama(base_url="http://localhost:11434", model="llama3.1"), -) -def test_build_model(mock_chat_ollama, component): - component.base_url = "http://localhost:11434" - component.model_name = "llama3.1" - component.mirostat = "Mirostat 2.0" - component.mirostat_eta = 0.2 # Ensure this is set as a float - component.mirostat_tau = 10.0 # Ensure this is set as a float - component.temperature = 0.2 - component.verbose = True - model = component.build_model() - assert isinstance(model, ChatOllama) - assert model.base_url == "http://localhost:11434" - assert model.model == "llama3.1" diff --git a/src/backend/tests/unit/graph/graph/test_base.py b/src/backend/tests/unit/graph/graph/test_base.py index 136dbdc56108..5d6cb037bf35 100644 --- a/src/backend/tests/unit/graph/graph/test_base.py +++ b/src/backend/tests/unit/graph/graph/test_base.py @@ -21,8 +21,8 @@ async def test_graph_not_prepared(): chat_input = ChatInput() chat_output = ChatOutput() graph = Graph() - graph.add_component("chat_input", chat_input) - graph.add_component("chat_output", chat_output) + graph.add_component(chat_input) + graph.add_component(chat_output) with pytest.raises(ValueError): await graph.astep() @@ -32,8 +32,8 @@ async def test_graph(): chat_input = ChatInput() chat_output = ChatOutput() graph = Graph() - graph.add_component("chat_input", chat_input) - graph.add_component("chat_output", chat_output) + graph.add_component(chat_input) + graph.add_component(chat_output) with pytest.warns(UserWarning, match="Graph has vertices but no edges"): graph.prepare() @@ -43,18 +43,18 @@ async def test_graph_with_edge(): chat_input = ChatInput() chat_output = ChatOutput() graph = Graph() - graph.add_component("chat_input", chat_input) - graph.add_component("chat_output", chat_output) - graph.add_component_edge("chat_input", (chat_input.outputs[0].name, chat_input.inputs[0].name), "chat_output") + input_id = graph.add_component(chat_input) + output_id = graph.add_component(chat_output) + graph.add_component_edge(input_id, (chat_input.outputs[0].name, chat_input.inputs[0].name), output_id) graph.prepare() - assert graph._run_queue == deque(["chat_input"]) + assert graph._run_queue == deque([input_id]) await graph.astep() - assert graph._run_queue == deque(["chat_output"]) + assert graph._run_queue == deque([output_id]) - assert graph.vertices[0].id == "chat_input" - assert graph.vertices[1].id == "chat_output" - assert graph.edges[0].source_id == "chat_input" - assert graph.edges[0].target_id == "chat_output" + assert graph.vertices[0].id == input_id + assert graph.vertices[1].id == output_id + assert graph.edges[0].source_id == input_id + assert graph.edges[0].target_id == output_id @pytest.mark.asyncio diff --git a/src/backend/tests/test_endpoints.py b/src/backend/tests/unit/test_endpoints.py similarity index 99% rename from src/backend/tests/test_endpoints.py rename to src/backend/tests/unit/test_endpoints.py index 130abed93d9b..f238a4a6a167 100644 --- a/src/backend/tests/test_endpoints.py +++ b/src/backend/tests/unit/test_endpoints.py @@ -427,7 +427,6 @@ def test_build_vertex_invalid_vertex_id(client, added_flow_with_prompt_and_histo assert response.status_code == 500 -@pytest.mark.api_key_required def test_successful_run_no_payload(client, simple_api_test, created_api_key): headers = {"x-api-key": created_api_key.api_key} flow_id = simple_api_test["id"] diff --git a/src/backend/tests/test_messages_endpoints.py b/src/backend/tests/unit/test_messages_endpoints.py similarity index 100% rename from src/backend/tests/test_messages_endpoints.py rename to src/backend/tests/unit/test_messages_endpoints.py diff --git a/src/backend/tests/test_schema.py b/src/backend/tests/unit/test_schema.py similarity index 100% rename from src/backend/tests/test_schema.py rename to src/backend/tests/unit/test_schema.py diff --git a/src/backend/tests/test_user.py b/src/backend/tests/unit/test_user.py similarity index 100% rename from src/backend/tests/test_user.py rename to src/backend/tests/unit/test_user.py diff --git a/src/backend/tests/test_webhook.py b/src/backend/tests/unit/test_webhook.py similarity index 100% rename from src/backend/tests/test_webhook.py rename to src/backend/tests/unit/test_webhook.py