refactor(tests): parameterize template tests and update timeout use (#9224)

* refactor: Simplify flow execution validation by removing unnecessary asyncio.wait_for calls

Updated the validate_flow_execution function to directly use the client.post and client.get methods with a timeout parameter, improving code readability and maintainability. This change eliminates redundant timeout handling while ensuring consistent timeout values across API calls.

* refactor: Enhance template tests for improved structure and validation

Refactored the template tests in `test_starter_projects.py` to utilize parameterization for better readability and maintainability. Introduced helper functions to retrieve template files and disabled tracing for all tests. Updated individual test methods to validate JSON structure, flow execution, and endpoint validation, ensuring comprehensive coverage of template functionality. This change streamlines the testing process and enhances the robustness of the test suite.

* refactor: Update project metadata and import paths in starter project JSON files

Modified the metadata section in multiple starter project JSON files to reflect updated code hashes and module paths, transitioning from 'lfx' to 'langflow' components. This change enhances consistency across the codebase and ensures that the correct modules are referenced for improved maintainability and clarity.

* chore: Update template test commands to utilize parallel execution

Modified the commands in the Makefile and CI workflows to include the `-n auto` option for pytest, enabling parallel test execution for the starter project template tests. This change enhances test performance and efficiency across the codebase.

* chore: Remove  news-aggregated.json file

Deleted the news-aggregated.json file

* Update test_template_validation.py

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Gabriel Luiz Freitas Almeida 2025-07-29 19:32:48 -03:00 committed by GitHub
commit cd4464d6b1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 666 additions and 307 deletions

View file

@ -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:

View file

@ -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
uv run pytest src/backend/tests/unit/template/test_starter_projects.py -v -n auto

View file

@ -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

View file

@ -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"
]
}

View file

@ -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"
]
}

View file

@ -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

View file

@ -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}")

View file

@ -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

View file

@ -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}")

View file

@ -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(

View file

@ -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}")

View file

@ -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: