diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c26710661..aeb38da64 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -232,7 +232,7 @@ jobs: - name: Test all starter project templates run: | - uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v + uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v -n auto # https://github.com/langchain-ai/langchain/blob/master/.github/workflows/check_diffs.yml ci_success: diff --git a/.github/workflows/template-tests.yml b/.github/workflows/template-tests.yml index 1ad1b9ad1..760739931 100644 --- a/.github/workflows/template-tests.yml +++ b/.github/workflows/template-tests.yml @@ -37,4 +37,4 @@ jobs: - name: Test all starter project templates run: | - uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v \ No newline at end of file + uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v -n auto \ No newline at end of file diff --git a/Makefile b/Makefile index a5c345d1c..c334a1846 100644 --- a/Makefile +++ b/Makefile @@ -169,7 +169,7 @@ tests: ## run unit, integration, coverage tests template_tests: ## run all starter project template tests @echo 'Running Starter Project Template Tests...' - @uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v + @uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v -n auto ###################### # CODE QUALITY diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json index d7c4aa7fd..165673b38 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Sequential Tasks Agents.json @@ -9,12 +9,16 @@ "dataType": "Prompt", "id": "Prompt-WvveL", "name": "prompt", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "system_prompt", "id": "Agent-X1iAT", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -33,12 +37,16 @@ "dataType": "Prompt", "id": "Prompt-6JL4E", "name": "prompt", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "system_prompt", "id": "Agent-EQcU8", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -57,12 +65,17 @@ "dataType": "Agent", "id": "Agent-EQcU8", "name": "response", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "finance_agent_output", "id": "Prompt-WvveL", - "inputTypes": ["Message", "Text"], + "inputTypes": [ + "Message", + "Text" + ], "type": "str" } }, @@ -81,12 +94,16 @@ "dataType": "ChatInput", "id": "ChatInput-NuUHZ", "name": "message", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "input_value", "id": "Agent-b7nmW", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -105,12 +122,16 @@ "dataType": "Prompt", "id": "Prompt-ajhmq", "name": "prompt", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "system_prompt", "id": "Agent-b7nmW", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -129,12 +150,16 @@ "dataType": "Agent", "id": "Agent-b7nmW", "name": "response", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "input_value", "id": "Agent-EQcU8", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -153,12 +178,17 @@ "dataType": "Agent", "id": "Agent-b7nmW", "name": "response", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "research_agent_output", "id": "Prompt-WvveL", - "inputTypes": ["Message", "Text"], + "inputTypes": [ + "Message", + "Text" + ], "type": "str" } }, @@ -177,12 +207,16 @@ "dataType": "CalculatorComponent", "id": "CalculatorComponent-0P2yI", "name": "component_as_tool", - "output_types": ["Tool"] + "output_types": [ + "Tool" + ] }, "targetHandle": { "fieldName": "tools", "id": "Agent-X1iAT", - "inputTypes": ["Tool"], + "inputTypes": [ + "Tool" + ], "type": "other" } }, @@ -201,12 +235,16 @@ "dataType": "YfinanceComponent", "id": "YfinanceComponent-hAneS", "name": "component_as_tool", - "output_types": ["Tool"] + "output_types": [ + "Tool" + ] }, "targetHandle": { "fieldName": "tools", "id": "Agent-EQcU8", - "inputTypes": ["Tool"], + "inputTypes": [ + "Tool" + ], "type": "other" } }, @@ -225,12 +263,16 @@ "dataType": "TavilySearchComponent", "id": "TavilySearchComponent-DTUmi", "name": "component_as_tool", - "output_types": ["Tool"] + "output_types": [ + "Tool" + ] }, "targetHandle": { "fieldName": "tools", "id": "Agent-b7nmW", - "inputTypes": ["Tool"], + "inputTypes": [ + "Tool" + ], "type": "other" } }, @@ -249,12 +291,18 @@ "dataType": "Agent", "id": "Agent-X1iAT", "name": "response", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "input_value", "id": "ChatOutput-gbqPo", - "inputTypes": ["Data", "DataFrame", "Message"], + "inputTypes": [ + "Data", + "DataFrame", + "Message" + ], "type": "other" } }, @@ -273,7 +321,9 @@ "display_name": "Finance Agent", "id": "Agent-EQcU8", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -322,7 +372,9 @@ "required_inputs": null, "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -354,7 +406,9 @@ "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -475,7 +529,9 @@ "display_name": "Input", "dynamic": false, "info": "The input provided by the user for the agent to process.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -683,7 +739,9 @@ "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -751,7 +809,9 @@ "display_name": "Tools", "dynamic": false, "info": "These are the tools that the agent can use to help with tasks.", - "input_types": ["Tool"], + "input_types": [ + "Tool" + ], "list": true, "list_add_label": "Add More", "name": "tools", @@ -812,7 +872,9 @@ "display_name": "Analysis & Editor Agent", "id": "Agent-X1iAT", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -861,7 +923,9 @@ "required_inputs": null, "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -893,7 +957,9 @@ "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1014,7 +1080,9 @@ "display_name": "Input", "dynamic": false, "info": "The input provided by the user for the agent to process.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1222,7 +1290,9 @@ "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1290,7 +1360,9 @@ "display_name": "Tools", "dynamic": false, "info": "These are the tools that the agent can use to help with tasks.", - "input_types": ["Tool"], + "input_types": [ + "Tool" + ], "list": true, "list_add_label": "Add More", "name": "tools", @@ -1351,7 +1423,9 @@ "display_name": "Prompt", "id": "Prompt-ajhmq", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": { @@ -1362,7 +1436,9 @@ "documentation": "", "edited": false, "error": null, - "field_order": ["template"], + "field_order": [ + "template" + ], "frozen": false, "full_path": null, "icon": "braces", @@ -1387,7 +1463,9 @@ "name": "prompt", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -1436,7 +1514,9 @@ "display_name": "Tool Placeholder", "dynamic": false, "info": "A placeholder input for tool mode.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "tool_placeholder", @@ -1481,7 +1561,9 @@ "display_name": "Prompt", "id": "Prompt-6JL4E", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": { @@ -1492,7 +1574,9 @@ "documentation": "", "edited": false, "error": null, - "field_order": ["template"], + "field_order": [ + "template" + ], "frozen": false, "full_path": null, "icon": "braces", @@ -1517,7 +1601,9 @@ "name": "prompt", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -1566,7 +1652,9 @@ "display_name": "Tool Placeholder", "dynamic": false, "info": "A placeholder input for tool mode.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "tool_placeholder", @@ -1611,18 +1699,25 @@ "display_name": "Prompt", "id": "Prompt-WvveL", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": { - "template": ["research_agent_output", "finance_agent_output"] + "template": [ + "research_agent_output", + "finance_agent_output" + ] }, "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", "documentation": "", "edited": false, "error": null, - "field_order": ["template"], + "field_order": [ + "template" + ], "frozen": false, "full_path": null, "icon": "braces", @@ -1647,7 +1742,9 @@ "name": "prompt", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -1680,7 +1777,10 @@ "fileTypes": [], "file_path": "", "info": "", - "input_types": ["Message", "Text"], + "input_types": [ + "Message", + "Text" + ], "list": false, "load_from_db": false, "multiline": true, @@ -1700,7 +1800,10 @@ "fileTypes": [], "file_path": "", "info": "", - "input_types": ["Message", "Text"], + "input_types": [ + "Message", + "Text" + ], "list": false, "load_from_db": false, "multiline": true, @@ -1736,7 +1839,9 @@ "display_name": "Tool Placeholder", "dynamic": false, "info": "A placeholder input for tool mode.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "tool_placeholder", @@ -1779,7 +1884,9 @@ "data": { "id": "ChatInput-NuUHZ", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -1817,7 +1924,9 @@ "name": "message", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -1830,7 +1939,9 @@ "display_name": "Background Color", "dynamic": false, "info": "The background color of the icon.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "background_color", @@ -1850,7 +1961,9 @@ "display_name": "Icon", "dynamic": false, "info": "The icon of the message.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "chat_icon", @@ -1954,7 +2067,10 @@ "dynamic": false, "info": "Type of sender.", "name": "sender", - "options": ["Machine", "User"], + "options": [ + "Machine", + "User" + ], "placeholder": "", "required": false, "show": true, @@ -1970,7 +2086,9 @@ "display_name": "Sender Name", "dynamic": false, "info": "Name of the sender.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "sender_name", @@ -1990,7 +2108,9 @@ "display_name": "Session ID", "dynamic": false, "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "session_id", @@ -2026,7 +2146,9 @@ "display_name": "Text Color", "dynamic": false, "info": "The text color of the name", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "name": "text_color", @@ -2106,7 +2228,9 @@ "display_name": "Researcher Agent", "id": "Agent-b7nmW", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -2155,7 +2279,9 @@ "required_inputs": null, "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -2187,7 +2313,9 @@ "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2308,7 +2436,9 @@ "display_name": "Input", "dynamic": false, "info": "The input provided by the user for the agent to process.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2516,7 +2646,9 @@ "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2584,7 +2716,9 @@ "display_name": "Tools", "dynamic": false, "info": "These are the tools that the agent can use to help with tasks.", - "input_types": ["Tool"], + "input_types": [ + "Tool" + ], "list": true, "list_add_label": "Add More", "name": "tools", @@ -2645,7 +2779,11 @@ "display_name": "Yahoo! Finance", "id": "YfinanceComponent-hAneS", "node": { - "base_classes": ["Data", "DataFrame", "Message"], + "base_classes": [ + "Data", + "DataFrame", + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -2653,7 +2791,11 @@ "display_name": "Yahoo! Finance", "documentation": "", "edited": false, - "field_order": ["symbol", "method", "num_news"], + "field_order": [ + "symbol", + "method", + "num_news" + ], "frozen": false, "icon": "trending-up", "legacy": false, @@ -2676,7 +2818,9 @@ "required_inputs": null, "selected": "Tool", "tool_mode": true, - "types": ["Tool"], + "types": [ + "Tool" + ], "value": "__UNDEFINED__" } ], @@ -2771,7 +2915,9 @@ "display_name": "Stock Symbol", "dynamic": false, "info": "The stock symbol to retrieve data for (e.g., AAPL, GOOG).", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2819,7 +2965,9 @@ "name": "fetch_content_dataframe", "readonly": false, "status": true, - "tags": ["fetch_content_dataframe"] + "tags": [ + "fetch_content_dataframe" + ] } ] } @@ -2847,7 +2995,9 @@ "data": { "id": "CalculatorComponent-0P2yI", "node": { - "base_classes": ["Data"], + "base_classes": [ + "Data" + ], "beta": false, "category": "tools", "conditional_paths": [], @@ -2856,7 +3006,9 @@ "display_name": "Calculator", "documentation": "", "edited": false, - "field_order": ["expression"], + "field_order": [ + "expression" + ], "frozen": false, "icon": "calculator", "key": "CalculatorComponent", @@ -2880,7 +3032,9 @@ "required_inputs": null, "selected": "Tool", "tool_mode": true, - "types": ["Tool"], + "types": [ + "Tool" + ], "value": "__UNDEFINED__" } ], @@ -2912,7 +3066,9 @@ "display_name": "Expression", "dynamic": false, "info": "The arithmetic expression to evaluate (e.g., '4*4*(33/22)+12-20').", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2960,7 +3116,9 @@ "name": "evaluate_expression", "readonly": false, "status": true, - "tags": ["evaluate_expression"] + "tags": [ + "evaluate_expression" + ] } ] } @@ -2988,7 +3146,10 @@ "data": { "id": "TavilySearchComponent-DTUmi", "node": { - "base_classes": ["Data", "Message"], + "base_classes": [ + "Data", + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -3028,7 +3189,9 @@ "required_inputs": null, "selected": "Tool", "tool_mode": true, - "types": ["Tool"], + "types": [ + "Tool" + ], "value": "__UNDEFINED__" } ], @@ -3112,7 +3275,9 @@ "display_name": "Exclude Domains", "dynamic": false, "info": "Comma-separated list of domains to exclude from the search results.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3151,7 +3316,9 @@ "display_name": "Include Domains", "dynamic": false, "info": "Comma-separated list of domains to include in the search results.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3226,7 +3393,9 @@ "display_name": "Search Query", "dynamic": false, "info": "The search query you want to execute with Tavily.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3250,7 +3419,10 @@ "dynamic": false, "info": "The depth of the search.", "name": "search_depth", - "options": ["basic", "advanced"], + "options": [ + "basic", + "advanced" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -3270,7 +3442,12 @@ "dynamic": false, "info": "The time range back from the current date to filter results.", "name": "time_range", - "options": ["day", "week", "month", "year"], + "options": [ + "day", + "week", + "month", + "year" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -3313,7 +3490,9 @@ "name": "fetch_content_dataframe", "readonly": false, "status": true, - "tags": ["fetch_content_dataframe"] + "tags": [ + "fetch_content_dataframe" + ] } ] }, @@ -3326,7 +3505,10 @@ "dynamic": false, "info": "The category of the search.", "name": "topic", - "options": ["general", "news"], + "options": [ + "general", + "news" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -3361,7 +3543,9 @@ "data": { "id": "ChatOutput-gbqPo", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "category": "outputs", "conditional_paths": [], @@ -3402,7 +3586,9 @@ "name": "message", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -3416,7 +3602,9 @@ "display_name": "Background Color", "dynamic": false, "info": "The background color of the icon.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3437,7 +3625,9 @@ "display_name": "Icon", "dynamic": false, "info": "The icon of the message.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3494,7 +3684,9 @@ "display_name": "Data Template", "dynamic": false, "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3515,7 +3707,11 @@ "display_name": "Inputs", "dynamic": false, "info": "Message to be passed as output.", - "input_types": ["Data", "DataFrame", "Message"], + "input_types": [ + "Data", + "DataFrame", + "Message" + ], "list": false, "list_add_label": "Add More", "name": "input_value", @@ -3536,7 +3732,10 @@ "dynamic": false, "info": "Type of sender.", "name": "sender", - "options": ["Machine", "User"], + "options": [ + "Machine", + "User" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -3553,7 +3752,9 @@ "display_name": "Sender Name", "dynamic": false, "info": "Name of the sender.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3574,7 +3775,9 @@ "display_name": "Session ID", "dynamic": false, "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3613,7 +3816,9 @@ "display_name": "Text Color", "dynamic": false, "info": "The text color of the name", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -3660,5 +3865,9 @@ "is_component": false, "last_tested_version": "1.4.3", "name": "Sequential Tasks Agents", - "tags": ["assistants", "agents", "web-scraping"] -} + "tags": [ + "assistants", + "agents", + "web-scraping" + ] +} \ No newline at end of file diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json b/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json index fa8b74256..1ec103133 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Youtube Analysis.json @@ -9,12 +9,16 @@ "dataType": "YouTubeCommentsComponent", "id": "YouTubeCommentsComponent-y3wJZ", "name": "comments", - "output_types": ["DataFrame"] + "output_types": [ + "DataFrame" + ] }, "targetHandle": { "fieldName": "df", "id": "BatchRunComponent-30WdR", - "inputTypes": ["DataFrame"], + "inputTypes": [ + "DataFrame" + ], "type": "other" } }, @@ -33,12 +37,16 @@ "dataType": "Prompt", "id": "Prompt-yqoLt", "name": "prompt", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "input_value", "id": "Agent-JRSRu", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -57,12 +65,18 @@ "dataType": "Agent", "id": "Agent-JRSRu", "name": "response", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "input_value", "id": "ChatOutput-vlskP", - "inputTypes": ["Data", "DataFrame", "Message"], + "inputTypes": [ + "Data", + "DataFrame", + "Message" + ], "type": "str" } }, @@ -81,12 +95,16 @@ "dataType": "YouTubeTranscripts", "id": "YouTubeTranscripts-TlFcG", "name": "component_as_tool", - "output_types": ["Tool"] + "output_types": [ + "Tool" + ] }, "targetHandle": { "fieldName": "tools", "id": "Agent-JRSRu", - "inputTypes": ["Tool"], + "inputTypes": [ + "Tool" + ], "type": "other" } }, @@ -105,12 +123,17 @@ "dataType": "BatchRunComponent", "id": "BatchRunComponent-30WdR", "name": "batch_results", - "output_types": ["DataFrame"] + "output_types": [ + "DataFrame" + ] }, "targetHandle": { "fieldName": "input_data", "id": "parser-k0Bpy", - "inputTypes": ["DataFrame", "Data"], + "inputTypes": [ + "DataFrame", + "Data" + ], "type": "other" } }, @@ -129,12 +152,16 @@ "dataType": "parser", "id": "parser-k0Bpy", "name": "parsed_text", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "analysis", "id": "Prompt-yqoLt", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -153,12 +180,16 @@ "dataType": "LanguageModelComponent", "id": "LanguageModelComponent-OvIt5", "name": "model_output", - "output_types": ["LanguageModel"] + "output_types": [ + "LanguageModel" + ] }, "targetHandle": { "fieldName": "model", "id": "BatchRunComponent-30WdR", - "inputTypes": ["LanguageModel"], + "inputTypes": [ + "LanguageModel" + ], "type": "other" } }, @@ -177,12 +208,16 @@ "dataType": "ChatInput", "id": "ChatInput-kaWcL", "name": "message", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "video_url", "id": "YouTubeCommentsComponent-y3wJZ", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -201,12 +236,16 @@ "dataType": "ChatInput", "id": "ChatInput-kaWcL", "name": "message", - "output_types": ["Message"] + "output_types": [ + "Message" + ] }, "targetHandle": { "fieldName": "url", "id": "Prompt-yqoLt", - "inputTypes": ["Message"], + "inputTypes": [ + "Message" + ], "type": "str" } }, @@ -223,7 +262,9 @@ "data": { "id": "BatchRunComponent-30WdR", "node": { - "base_classes": ["DataFrame"], + "base_classes": [ + "DataFrame" + ], "beta": false, "category": "helpers", "conditional_paths": [], @@ -232,7 +273,12 @@ "display_name": "Batch Run", "documentation": "", "edited": false, - "field_order": ["model", "system_message", "df", "column_name"], + "field_order": [ + "model", + "system_message", + "df", + "column_name" + ], "frozen": false, "icon": "List", "key": "BatchRunComponent", @@ -254,7 +300,9 @@ "name": "batch_results", "selected": "DataFrame", "tool_mode": true, - "types": ["DataFrame"], + "types": [ + "DataFrame" + ], "value": "__UNDEFINED__" } ], @@ -305,7 +353,9 @@ "display_name": "DataFrame", "dynamic": false, "info": "The DataFrame whose column (specified by 'column_name') we'll treat as text messages.", - "input_types": ["DataFrame"], + "input_types": [ + "DataFrame" + ], "list": false, "list_add_label": "Add More", "name": "df", @@ -343,7 +393,9 @@ "display_name": "Language Model", "dynamic": false, "info": "Connect the 'Language Model' output from your LLM component here.", - "input_types": ["LanguageModel"], + "input_types": [ + "LanguageModel" + ], "list": false, "list_add_label": "Add More", "name": "model", @@ -361,7 +413,9 @@ "display_name": "Output Column Name", "dynamic": false, "info": "Name of the column where the model's response will be stored.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -382,7 +436,9 @@ "display_name": "Instructions", "dynamic": false, "info": "Multi-line system instruction for all rows in the DataFrame.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -422,7 +478,9 @@ "data": { "id": "YouTubeCommentsComponent-y3wJZ", "node": { - "base_classes": ["DataFrame"], + "base_classes": [ + "DataFrame" + ], "beta": false, "category": "youtube", "conditional_paths": [], @@ -460,7 +518,9 @@ "name": "comments", "selected": "DataFrame", "tool_mode": true, - "types": ["DataFrame"], + "types": [ + "DataFrame" + ], "value": "__UNDEFINED__" } ], @@ -566,7 +626,10 @@ "dynamic": false, "info": "Sort comments by time or relevance.", "name": "sort_by", - "options": ["time", "relevance"], + "options": [ + "time", + "relevance" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -583,7 +646,9 @@ "display_name": "Video URL", "dynamic": false, "info": "The URL of the YouTube video to get comments from.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -622,7 +687,9 @@ "data": { "id": "Agent-JRSRu", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -673,7 +740,9 @@ "required_inputs": null, "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -705,7 +774,9 @@ "display_name": "Agent Description [Deprecated]", "dynamic": false, "info": "The description of the agent. This is only used when in Tool Mode. Defaults to 'A helpful assistant with access to the following tools:' and tools are added dynamically. This feature is deprecated and will be removed in future versions.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -826,7 +897,9 @@ "display_name": "Input", "dynamic": false, "info": "The input provided by the user for the agent to process.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1034,7 +1107,9 @@ "display_name": "Agent Instructions", "dynamic": false, "info": "System Prompt: Initial instructions and context provided to guide the agent's behavior.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1102,7 +1177,9 @@ "display_name": "Tools", "dynamic": false, "info": "These are the tools that the agent can use to help with tasks.", - "input_types": ["Tool"], + "input_types": [ + "Tool" + ], "list": true, "list_add_label": "Add More", "name": "tools", @@ -1156,18 +1233,26 @@ "data": { "id": "Prompt-yqoLt", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": { - "template": ["url", "analysis"] + "template": [ + "url", + "analysis" + ] }, "description": "Create a prompt template with dynamic variables.", "display_name": "Prompt", "documentation": "", "edited": false, "error": null, - "field_order": ["template", "tool_placeholder"], + "field_order": [ + "template", + "tool_placeholder" + ], "frozen": false, "full_path": null, "icon": "braces", @@ -1190,7 +1275,9 @@ "name": "prompt", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -1205,7 +1292,9 @@ "fileTypes": [], "file_path": "", "info": "", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "multiline": true, @@ -1259,7 +1348,9 @@ "display_name": "Tool Placeholder", "dynamic": false, "info": "A placeholder input for tool mode.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1282,7 +1373,9 @@ "fileTypes": [], "file_path": "", "info": "", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "load_from_db": false, "multiline": true, @@ -1318,7 +1411,9 @@ "data": { "id": "ChatOutput-vlskP", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "category": "outputs", "conditional_paths": [], @@ -1359,7 +1454,9 @@ "name": "message", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -1373,7 +1470,9 @@ "display_name": "Background Color", "dynamic": false, "info": "The background color of the icon.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1394,7 +1493,9 @@ "display_name": "Icon", "dynamic": false, "info": "The icon of the message.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1451,7 +1552,9 @@ "display_name": "Data Template", "dynamic": false, "info": "Template to convert Data to Text. If left empty, it will be dynamically set to the Data's text key.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1472,7 +1575,11 @@ "display_name": "Inputs", "dynamic": false, "info": "Message to be passed as output.", - "input_types": ["Data", "DataFrame", "Message"], + "input_types": [ + "Data", + "DataFrame", + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1496,7 +1603,10 @@ "dynamic": false, "info": "Type of sender.", "name": "sender", - "options": ["Machine", "User"], + "options": [ + "Machine", + "User" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -1513,7 +1623,9 @@ "display_name": "Sender Name", "dynamic": false, "info": "Name of the sender.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1534,7 +1646,9 @@ "display_name": "Session ID", "dynamic": false, "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1573,7 +1687,9 @@ "display_name": "Text Color", "dynamic": false, "info": "The text color of the name", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1611,7 +1727,11 @@ "data": { "id": "YouTubeTranscripts-TlFcG", "node": { - "base_classes": ["Data", "DataFrame", "Message"], + "base_classes": [ + "Data", + "DataFrame", + "Message" + ], "beta": false, "conditional_paths": [], "custom_fields": {}, @@ -1619,7 +1739,11 @@ "display_name": "YouTube Transcripts", "documentation": "", "edited": false, - "field_order": ["url", "chunk_size_seconds", "translation"], + "field_order": [ + "url", + "chunk_size_seconds", + "translation" + ], "frozen": false, "icon": "YouTube", "last_updated": "2025-07-07T14:52:15.000Z", @@ -1644,7 +1768,9 @@ "required_inputs": null, "selected": "Tool", "tool_mode": true, - "types": ["Tool"], + "types": [ + "Tool" + ], "value": "__UNDEFINED__" } ], @@ -1719,7 +1845,9 @@ "name": "get_dataframe_output", "readonly": false, "status": true, - "tags": ["get_dataframe_output"] + "tags": [ + "get_dataframe_output" + ] }, { "args": { @@ -1735,7 +1863,9 @@ "name": "get_message_output", "readonly": false, "status": true, - "tags": ["get_message_output"] + "tags": [ + "get_message_output" + ] }, { "args": { @@ -1751,7 +1881,9 @@ "name": "get_data_output", "readonly": false, "status": true, - "tags": ["get_data_output"] + "tags": [ + "get_data_output" + ] } ] }, @@ -1795,7 +1927,9 @@ "display_name": "Video URL", "dynamic": false, "info": "Enter the YouTube video URL to get transcripts from.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1864,7 +1998,9 @@ "data": { "id": "parser-k0Bpy", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "category": "processing", "conditional_paths": [], @@ -1873,7 +2009,12 @@ "display_name": "Parser", "documentation": "", "edited": false, - "field_order": ["mode", "pattern", "input_data", "sep"], + "field_order": [ + "mode", + "pattern", + "input_data", + "sep" + ], "frozen": false, "icon": "braces", "key": "parser", @@ -1891,7 +2032,9 @@ "name": "parsed_text", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -1923,7 +2066,10 @@ "display_name": "Data or DataFrame", "dynamic": false, "info": "Accepts either a DataFrame or a Data object.", - "input_types": ["DataFrame", "Data"], + "input_types": [ + "DataFrame", + "Data" + ], "list": false, "list_add_label": "Add More", "name": "input_data", @@ -1942,7 +2088,10 @@ "dynamic": false, "info": "Convert into raw string instead of using a template.", "name": "mode", - "options": ["Parser", "Stringify"], + "options": [ + "Parser", + "Stringify" + ], "placeholder": "", "real_time_refresh": true, "required": false, @@ -1960,7 +2109,9 @@ "display_name": "Template", "dynamic": true, "info": "Use variables within curly brackets to extract column values for DataFrames or key values for Data.For example: `Name: {Name}, Age: {Age}, Country: {Country}`", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -1982,7 +2133,9 @@ "display_name": "Separator", "dynamic": false, "info": "String used to separate rows/items.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2021,7 +2174,10 @@ "data": { "id": "LanguageModelComponent-OvIt5", "node": { - "base_classes": ["LanguageModel", "Message"], + "base_classes": [ + "LanguageModel", + "Message" + ], "beta": false, "category": "models", "conditional_paths": [], @@ -2067,7 +2223,9 @@ "required_inputs": null, "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" }, { @@ -2081,7 +2239,9 @@ "required_inputs": null, "selected": "LanguageModel", "tool_mode": true, - "types": ["LanguageModel"], + "types": [ + "LanguageModel" + ], "value": "__UNDEFINED__" } ], @@ -2132,7 +2292,9 @@ "display_name": "Input", "dynamic": false, "info": "The input text to send to the model", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2188,7 +2350,11 @@ "dynamic": false, "info": "Select the model provider", "name": "provider", - "options": ["OpenAI", "Anthropic", "Google"], + "options": [ + "OpenAI", + "Anthropic", + "Google" + ], "options_metadata": [ { "icon": "OpenAI" @@ -2236,7 +2402,9 @@ "display_name": "System Message", "dynamic": false, "info": "A system message that helps set the behavior of the assistant", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2304,7 +2472,9 @@ "data": { "id": "ChatInput-kaWcL", "node": { - "base_classes": ["Message"], + "base_classes": [ + "Message" + ], "beta": false, "category": "input_output", "conditional_paths": [], @@ -2345,7 +2515,9 @@ "name": "message", "selected": "Message", "tool_mode": true, - "types": ["Message"], + "types": [ + "Message" + ], "value": "__UNDEFINED__" } ], @@ -2359,7 +2531,9 @@ "display_name": "Background Color", "dynamic": false, "info": "The background color of the icon.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2380,7 +2554,9 @@ "display_name": "Icon", "dynamic": false, "info": "The icon of the message.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2489,7 +2665,10 @@ "dynamic": false, "info": "Type of sender.", "name": "sender", - "options": ["Machine", "User"], + "options": [ + "Machine", + "User" + ], "options_metadata": [], "placeholder": "", "required": false, @@ -2507,7 +2686,9 @@ "display_name": "Sender Name", "dynamic": false, "info": "Name of the sender.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2528,7 +2709,9 @@ "display_name": "Session ID", "dynamic": false, "info": "The session ID of the chat. If empty, the current session ID parameter will be used.", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2567,7 +2750,9 @@ "display_name": "Text Color", "dynamic": false, "info": "The text color of the name", - "input_types": ["Message"], + "input_types": [ + "Message" + ], "list": false, "list_add_label": "Add More", "load_from_db": false, @@ -2614,5 +2799,8 @@ "is_component": false, "last_tested_version": "1.4.3", "name": "YouTube Analysis", - "tags": ["agents", "assistants"] -} + "tags": [ + "agents", + "assistants" + ] +} \ No newline at end of file diff --git a/src/backend/base/langflow/utils/template_validation.py b/src/backend/base/langflow/utils/template_validation.py index ac5b523b8..17de74231 100644 --- a/src/backend/base/langflow/utils/template_validation.py +++ b/src/backend/base/langflow/utils/template_validation.py @@ -155,9 +155,7 @@ async def validate_flow_execution( try: # Create a flow from the template with timeout - create_response = await asyncio.wait_for( - client.post("api/v1/flows/", json=template_data, headers=headers), timeout=10.0 - ) + create_response = await client.post("api/v1/flows/", json=template_data, headers=headers, timeout=10) if create_response.status_code != 201: # noqa: PLR2004 errors.append(f"{filename}: Failed to create flow: {create_response.status_code}") @@ -167,9 +165,7 @@ async def validate_flow_execution( try: # Build the flow with timeout - build_response = await asyncio.wait_for( - client.post(f"api/v1/build/{flow_id}/flow", json={}, headers=headers), timeout=15.0 - ) + build_response = await client.post(f"api/v1/build/{flow_id}/flow", json={}, headers=headers, timeout=10) if build_response.status_code != 200: # noqa: PLR2004 errors.append(f"{filename}: Failed to build flow: {build_response.status_code}") @@ -179,9 +175,7 @@ async def validate_flow_execution( # Get build events to validate execution events_headers = {**headers, "Accept": "application/x-ndjson"} - events_response = await asyncio.wait_for( - client.get(f"api/v1/build/{job_id}/events", headers=events_headers), timeout=10.0 - ) + events_response = await client.get(f"api/v1/build/{job_id}/events", headers=events_headers, timeout=10) if events_response.status_code != 200: # noqa: PLR2004 errors.append(f"{filename}: Failed to get build events: {events_response.status_code}") @@ -193,7 +187,7 @@ async def validate_flow_execution( finally: # Clean up the flow with timeout try: # noqa: SIM105 - await asyncio.wait_for(client.delete(f"api/v1/flows/{flow_id}", headers=headers), timeout=5.0) + await client.delete(f"api/v1/flows/{flow_id}", headers=headers, timeout=10) except asyncio.TimeoutError: # Log but don't fail if cleanup times out pass diff --git a/src/backend/tests/conftest.py b/src/backend/tests/conftest.py index a144d52a7..c156442b6 100644 --- a/src/backend/tests/conftest.py +++ b/src/backend/tests/conftest.py @@ -168,11 +168,11 @@ async def _delete_transactions_and_vertex_builds(session, flows: list[Flow]): continue try: await delete_vertex_builds_by_flow_id(session, flow_id) - except Exception as e: # noqa: BLE001 + except Exception as e: logger.debug(f"Error deleting vertex builds for flow {flow_id}: {e}") try: await delete_transactions_by_flow_id(session, flow_id) - except Exception as e: # noqa: BLE001 + except Exception as e: logger.debug(f"Error deleting transactions for flow {flow_id}: {e}") @@ -474,7 +474,7 @@ async def active_user(client): # noqa: ARG001 user = await session.get(User, user.id, options=[selectinload(User.flows)]) await _delete_transactions_and_vertex_builds(session, user.flows) await session.commit() - except Exception as e: # noqa: BLE001 + except Exception as e: logger.exception(f"Error deleting transactions and vertex builds for user: {e}") try: @@ -482,7 +482,7 @@ async def active_user(client): # noqa: ARG001 user = await session.get(User, user.id) await session.delete(user) await session.commit() - except Exception as e: # noqa: BLE001 + except Exception as e: logger.exception(f"Error deleting user: {e}") diff --git a/src/backend/tests/integration/components/astra/test_astra_component.py b/src/backend/tests/integration/components/astra/test_astra_component.py index c324b0d1b..b8c7da3dc 100644 --- a/src/backend/tests/integration/components/astra/test_astra_component.py +++ b/src/backend/tests/integration/components/astra/test_astra_component.py @@ -39,7 +39,7 @@ def astradb_client(): for collection in ALL_COLLECTIONS: try: # noqa: SIM105 client.drop_collection(collection) - except Exception: # noqa: BLE001, S110 + except Exception: # noqa: S110 pass diff --git a/src/backend/tests/locust/locustfile.py b/src/backend/tests/locust/locustfile.py index 6d77bc396..ab4cd612a 100644 --- a/src/backend/tests/locust/locustfile.py +++ b/src/backend/tests/locust/locustfile.py @@ -119,7 +119,7 @@ class FlowRunUser(FastHttpUser): error_msg = f"Unexpected status code: {response.status_code}, Response: {error_text[:200]}" response.failure(error_msg) self.log_error(endpoint, Exception(error_msg), response_time) - except Exception as e: # noqa: BLE001 + except Exception as e: response_time = (time.time() - start_time) * 1000 self.log_error(endpoint, e, response_time) response.failure(f"Error: {e}") diff --git a/src/backend/tests/unit/components/agents/test_agent_component.py b/src/backend/tests/unit/components/agents/test_agent_component.py index b028c3a4d..acaa53029 100644 --- a/src/backend/tests/unit/components/agents/test_agent_component.py +++ b/src/backend/tests/unit/components/agents/test_agent_component.py @@ -330,7 +330,7 @@ class TestAgentComponentWithClient(ComponentTestBaseWithClient): if "4" not in response_text: failed_models[model_name] = f"Expected '4' in response but got: {response_text}" - except Exception as e: # noqa: BLE001 + except Exception as e: failed_models[model_name] = f"Exception occurred: {e!s}" assert not failed_models, "The following models failed the test:\n" + "\n".join( diff --git a/src/backend/tests/unit/template/test_starter_projects.py b/src/backend/tests/unit/template/test_starter_projects.py index 2ad939267..7ea56e032 100644 --- a/src/backend/tests/unit/template/test_starter_projects.py +++ b/src/backend/tests/unit/template/test_starter_projects.py @@ -9,7 +9,6 @@ Tests all JSON templates in the starter_projects folder to ensure they: Validates that templates work correctly and prevent unexpected breakage. """ -import asyncio import json from pathlib import Path @@ -28,6 +27,24 @@ def get_starter_projects_path() -> Path: return Path("src/backend/base/langflow/initial_setup/starter_projects") +def get_template_files(): + """Get all template files for parameterization.""" + return list(get_starter_projects_path().glob("*.json")) + + +def get_basic_template_files(): + """Get basic template files for parameterization.""" + path = get_starter_projects_path() + basic_templates = ["Basic Prompting.json", "Basic Prompt Chaining.json"] + return [path / name for name in basic_templates if (path / name).exists()] + + +@pytest.fixture(autouse=True) +def disable_tracing(monkeypatch): + """Disable tracing for all template tests.""" + monkeypatch.setenv("LANGFLOW_DEACTIVATE_TRACING", "true") + + class TestStarterProjects: """Test all starter project templates.""" @@ -36,129 +53,80 @@ class TestStarterProjects: path = get_starter_projects_path() assert path.exists(), f"Directory not found: {path}" - templates = list(path.glob("*.json")) + templates = get_template_files() assert len(templates) > 0, "No template files found" - def test_all_templates_valid_json(self): - """Test all templates are valid JSON.""" - path = get_starter_projects_path() - templates = list(path.glob("*.json")) + @pytest.mark.parametrize("template_file", get_template_files(), ids=lambda x: x.name) + def test_template_valid_json(self, template_file): + """Test template is valid JSON.""" + with template_file.open(encoding="utf-8") as f: + try: + json.load(f) + except json.JSONDecodeError as e: + pytest.fail(f"Invalid JSON in {template_file.name}: {e}") - for template_file in templates: - with template_file.open(encoding="utf-8") as f: - try: - json.load(f) - except json.JSONDecodeError as e: - pytest.fail(f"Invalid JSON in {template_file.name}: {e}") + @pytest.mark.parametrize("template_file", get_template_files(), ids=lambda x: x.name) + def test_template_structure(self, template_file): + """Test template has required structure.""" + with template_file.open(encoding="utf-8") as f: + template_data = json.load(f) - def test_all_templates_structure(self): - """Test all templates have required structure.""" - path = get_starter_projects_path() - templates = list(path.glob("*.json")) + errors = validate_template_structure(template_data, template_file.name) + if errors: + error_msg = "\n".join(errors) + pytest.fail(f"Template structure errors in {template_file.name}:\n{error_msg}") - all_errors = [] - for template_file in templates: - with template_file.open(encoding="utf-8") as f: - template_data = json.load(f) + @pytest.mark.parametrize("template_file", get_template_files(), ids=lambda x: x.name) + def test_template_can_build_flow(self, template_file): + """Test template can be built into working flow.""" + with template_file.open(encoding="utf-8") as f: + template_data = json.load(f) - errors = validate_template_structure(template_data, template_file.name) - all_errors.extend(errors) - - if all_errors: - error_msg = "\n".join(all_errors) - pytest.fail(f"Template structure errors:\n{error_msg}") - - def test_all_templates_can_build_flow(self): - """Test all templates can be built into working flows.""" - path = get_starter_projects_path() - templates = list(path.glob("*.json")) - - all_errors = [] - for template_file in templates: - with template_file.open(encoding="utf-8") as f: - template_data = json.load(f) - - errors = validate_flow_can_build(template_data, template_file.name) - all_errors.extend(errors) - - if all_errors: - error_msg = "\n".join(all_errors) - pytest.fail(f"Flow build errors:\n{error_msg}") + errors = validate_flow_can_build(template_data, template_file.name) + if errors: + error_msg = "\n".join(errors) + pytest.fail(f"Flow build errors in {template_file.name}:\n{error_msg}") @pytest.mark.asyncio - async def test_all_templates_validate_endpoint(self, client, logged_in_headers): - """Test all templates using the validate endpoint.""" - path = get_starter_projects_path() - templates = list(path.glob("*.json")) + @pytest.mark.parametrize("template_file", get_template_files(), ids=lambda x: x.name) + async def test_template_validate_endpoint(self, template_file, client, logged_in_headers): + """Test template using the validate endpoint.""" + with template_file.open(encoding="utf-8") as f: + template_data = json.load(f) - all_errors = [] - for template_file in templates: + errors = await validate_flow_execution(client, template_data, template_file.name, logged_in_headers) + if errors: + error_msg = "\n".join(errors) + pytest.fail(f"Endpoint validation errors in {template_file.name}:\n{error_msg}") + + @pytest.mark.asyncio + @pytest.mark.parametrize("template_file", get_template_files(), ids=lambda x: x.name) + async def test_template_flow_execution(self, template_file, client, logged_in_headers): + """Test template can execute successfully.""" + try: with template_file.open(encoding="utf-8") as f: template_data = json.load(f) errors = await validate_flow_execution(client, template_data, template_file.name, logged_in_headers) - all_errors.extend(errors) + if errors: + error_msg = "\n".join(errors) + pytest.fail(f"Template execution errors in {template_file.name}:\n{error_msg}") - if all_errors: - error_msg = "\n".join(all_errors) - pytest.fail(f"Endpoint validation errors:\n{error_msg}") + except (ValueError, TypeError, KeyError, AttributeError, OSError, json.JSONDecodeError) as e: + pytest.fail(f"{template_file.name}: Unexpected error during validation: {e!s}") @pytest.mark.asyncio - async def test_all_templates_flow_execution(self, client, logged_in_headers): - """Test all templates can execute successfully.""" - path = get_starter_projects_path() - templates = list(path.glob("*.json")) + @pytest.mark.parametrize("template_file", get_basic_template_files(), ids=lambda x: x.name) + async def test_basic_template_flow_execution(self, template_file, client, logged_in_headers): + """Test basic template can execute successfully.""" + try: + with template_file.open(encoding="utf-8") as f: + template_data = json.load(f) - all_errors = [] + errors = await validate_flow_execution(client, template_data, template_file.name, logged_in_headers) + if errors: + error_msg = "\n".join(errors) + pytest.fail(f"Basic template execution errors in {template_file.name}:\n{error_msg}") - # Process templates in chunks to avoid timeout issues - chunk_size = 5 - template_chunks = [templates[i : i + chunk_size] for i in range(0, len(templates), chunk_size)] - - for chunk in template_chunks: - for template_file in chunk: - try: - with template_file.open(encoding="utf-8") as f: - template_data = json.load(f) - - errors = await validate_flow_execution(client, template_data, template_file.name, logged_in_headers) - all_errors.extend(errors) - - except (ValueError, TypeError, KeyError, AttributeError, OSError, json.JSONDecodeError) as e: - error_msg = f"{template_file.name}: Unexpected error during validation: {e!s}" - all_errors.append(error_msg) - - # Brief pause between chunks to avoid overwhelming the system - await asyncio.sleep(0.5) - - # All templates must pass - no failures allowed - if all_errors: - error_msg = "\n".join(all_errors) - pytest.fail(f"Template execution errors:\n{error_msg}") - - @pytest.mark.asyncio - async def test_basic_templates_flow_execution(self, client, logged_in_headers): - """Test basic templates can execute successfully.""" - path = get_starter_projects_path() - - # Only test basic templates that should reliably work - basic_templates = ["Basic Prompting.json", "Basic Prompt Chaining.json"] - - all_errors = [] - for template_name in basic_templates: - template_file = path / template_name - if template_file.exists(): - try: - with template_file.open(encoding="utf-8") as f: - template_data = json.load(f) - - errors = await validate_flow_execution(client, template_data, template_name, logged_in_headers) - all_errors.extend(errors) - - except (ValueError, TypeError, KeyError, AttributeError, OSError, json.JSONDecodeError) as e: - all_errors.append(f"{template_name}: Unexpected error during validation: {e!s}") - - # All basic templates must pass - no failures allowed - if all_errors: - error_msg = "\n".join(all_errors) - pytest.fail(f"Basic template execution errors:\n{error_msg}") + except (ValueError, TypeError, KeyError, AttributeError, OSError, json.JSONDecodeError) as e: + pytest.fail(f"{template_file.name}: Unexpected error during validation: {e!s}") diff --git a/src/backend/tests/unit/utils/test_template_validation.py b/src/backend/tests/unit/utils/test_template_validation.py index 86615bab2..0ef3f859d 100644 --- a/src/backend/tests/unit/utils/test_template_validation.py +++ b/src/backend/tests/unit/utils/test_template_validation.py @@ -464,14 +464,14 @@ class TestValidateFlowExecution: mock_client.delete.return_value = Mock() template_data = {"nodes": [], "edges": []} - headers = {"Authorization": "Bearer token"} + headers = {"Authorization": "Bearer token", "timeout": 10} errors = await validate_flow_execution(mock_client, template_data, "test.json", headers) assert len(errors) == 1 assert "Flow execution validation failed: Build error" in errors[0] # Verify cleanup was called - mock_client.delete.assert_called_once_with("api/v1/flows/flow123", headers=headers) + mock_client.delete.assert_called_once_with("api/v1/flows/flow123", headers=headers, timeout=10) class TestValidateEventStream: