diff --git a/src/backend/base/langflow/custom/dependency_analyzer.py b/src/backend/base/langflow/custom/dependency_analyzer.py new file mode 100644 index 000000000..1b418ecf5 --- /dev/null +++ b/src/backend/base/langflow/custom/dependency_analyzer.py @@ -0,0 +1,165 @@ +"""Dependency analysis utilities for custom components.""" + +from __future__ import annotations + +import ast +import importlib.metadata as md +import sys +from dataclasses import asdict, dataclass +from functools import lru_cache + +try: + STDLIB_MODULES: set[str] = set(sys.stdlib_module_names) # 3.10+ +except AttributeError: + # Fallback heuristic if running on <3.10 + STDLIB_MODULES = set(sys.builtin_module_names) + + +@dataclass(frozen=True) +class DependencyInfo: + """Information about a dependency imported in Python code.""" + + name: str # package name (e.g. "numpy", "requests") + version: str | None # package version if available + is_local: bool # True for relative imports (from .module import ...) + + +def _top_level(pkg: str) -> str: + """Extract top-level package name.""" + return pkg.split(".", 1)[0] + + +def _is_relative(module: str | None) -> bool: + """Check if module is a relative import.""" + return module is not None and module.startswith(".") + + +class _ImportVisitor(ast.NodeVisitor): + """AST visitor to extract import information.""" + + def __init__(self): + self.results: list[DependencyInfo] = [] + + def visit_Import(self, node: ast.Import): + for alias in node.names: + full = alias.name + dep = DependencyInfo( + name=_top_level(full), + version=None, + is_local=False, # Regular imports are not local + ) + self.results.append(dep) + + def visit_ImportFrom(self, node: ast.ImportFrom): + # Reconstruct full module name with proper relative import handling + if node.level > 0: + # Relative import: from .module import x or from ..parent import x + dots = "." * node.level + full_module = dots + (node.module or "") + else: + # Absolute import: from module import x + full_module = node.module or "" + for _alias in node.names: + dep = DependencyInfo( + name=_top_level(full_module.lstrip(".")) if full_module else "", + version=None, + is_local=_is_relative(full_module), # Check if it's a relative import + ) + self.results.append(dep) + + +def _classify_dependency(dep: DependencyInfo) -> DependencyInfo: + """Resolve version information for external dependencies.""" + version = None + if not dep.is_local and dep.name: + version = _get_distribution_version(dep.name) + + return DependencyInfo( + name=dep.name, + version=version, + is_local=dep.is_local, + ) + + +def analyze_dependencies(source: str, *, resolve_versions: bool = True) -> list[dict]: + """Return a list[dict] of dependencies imported by the given Python source code. + + Args: + source: Python source code string + resolve_versions: Whether to resolve version information + + Returns: + List of dependency dictionaries + """ + code = source + + # Parse the code and extract imports + tree = ast.parse(code) + visitor = _ImportVisitor() + visitor.visit(tree) + + # Process and deduplicate dependencies by package name only + unique_packages: dict[str, DependencyInfo] = {} + for raw_dep in visitor.results: + processed_dep = _classify_dependency(raw_dep) if resolve_versions else raw_dep + + # Skip stdlib imports and local imports - we only care about external dependencies + if processed_dep.name in STDLIB_MODULES or processed_dep.is_local: + continue + + # Deduplicate by package name only (not full_module) + if processed_dep.name not in unique_packages: + unique_packages[processed_dep.name] = processed_dep + + return [asdict(d) for d in unique_packages.values()] + + +def analyze_component_dependencies(component_code: str) -> dict: + """Analyze dependencies for a custom component. + + Args: + component_code: The component's source code + + Returns: + Dictionary with dependency analysis results + """ + try: + deps = analyze_dependencies(component_code, resolve_versions=True) + + return { + "total_dependencies": len(deps), + "dependencies": [{"name": d["name"], "version": d["version"]} for d in deps if d["name"]], + } + except (SyntaxError, TypeError, ValueError, ImportError): + # If analysis fails, return minimal info + return { + "total_dependencies": 0, + "dependencies": [], + } + + +# Cache the expensive packages_distributions() call globally +@lru_cache(maxsize=1) +def _get_packages_distributions(): + """Cache the expensive packages_distributions() call.""" + try: + return md.packages_distributions() + except (OSError, AttributeError, ValueError): + return {} + + +# Helper function to cache version lookups for installed distributions +@lru_cache(maxsize=128) +def _get_distribution_version(import_name: str): + try: + # Reverse-lookup: which distribution(s) provide this importable name? + reverse_map = _get_packages_distributions() + dist_names = reverse_map.get(import_name) + if not dist_names: + return None + + # Take the first matching distribution + dist_name = dist_names[0] + return md.distribution(dist_name).version + except (ImportError, AttributeError, OSError, ValueError): + return None diff --git a/src/backend/base/langflow/custom/utils.py b/src/backend/base/langflow/custom/utils.py index fe08726c4..5d7fcdc85 100644 --- a/src/backend/base/langflow/custom/utils.py +++ b/src/backend/base/langflow/custom/utils.py @@ -1,4 +1,6 @@ # mypy: ignore-errors +from __future__ import annotations + import ast import asyncio import contextlib @@ -7,14 +9,13 @@ import inspect import re import traceback from pathlib import Path -from typing import Any -from uuid import UUID +from typing import TYPE_CHECKING, Any from fastapi import HTTPException from pydantic import BaseModel from langflow.custom.custom_component.component import Component -from langflow.custom.custom_component.custom_component import CustomComponent +from langflow.custom.dependency_analyzer import analyze_component_dependencies from langflow.custom.directory_reader.utils import ( abuild_custom_component_list_from_path, build_custom_component_list_from_path, @@ -32,6 +33,11 @@ from langflow.type_extraction.type_extraction import extract_inner_type from langflow.utils import validate from langflow.utils.util import get_base_classes +if TYPE_CHECKING: + from uuid import UUID + + from langflow.custom.custom_component.custom_component import CustomComponent + def _generate_code_hash(source_code: str, modname: str) -> str: """Generate a hash of the component source code. @@ -488,6 +494,15 @@ def build_custom_component_template_from_inputs( # ! This should be removed when we have a better way to handle this frontend_node.set_base_classes_from_outputs() reorder_fields(frontend_node, cc_instance._get_field_order()) + frontend_node = build_component_metadata(frontend_node, cc_instance, module_name, ctype_name) + + return frontend_node.to_dict(keep_name=False), cc_instance + + +def build_component_metadata( + frontend_node: CustomComponentFrontendNode, custom_component: CustomComponent, module_name: str, ctype_name: str +): + """Build the metadata for a custom component.""" if module_name: frontend_node.metadata["module"] = module_name else: @@ -502,7 +517,19 @@ def build_custom_component_template_from_inputs( except Exception as exc: # noqa: BLE001 logger.debug(f"Error generating code hash for {custom_component.__class__.__name__}", exc_info=exc) - return frontend_node.to_dict(keep_name=False), cc_instance + # Analyze component dependencies + try: + dependency_info = analyze_component_dependencies(custom_component._code) + frontend_node.metadata["dependencies"] = dependency_info + except (SyntaxError, TypeError, ValueError, ImportError) as exc: + logger.warning(f"Failed to analyze dependencies for component {ctype_name}: {exc}") + # Set minimal dependency info on failure + frontend_node.metadata["dependencies"] = { + "total_dependencies": 0, + "dependencies": [], + } + + return frontend_node def build_custom_component_template( @@ -562,18 +589,9 @@ def build_custom_component_template( reorder_fields(frontend_node, custom_instance._get_field_order()) if module_name: - frontend_node.metadata["module"] = module_name - else: - module_name = get_module_name_from_display_name(frontend_node.display_name) - frontend_node.metadata["module"] = f"custom_components.{module_name}" - - # Generate code hash for cache invalidation and debugging - try: - code_hash = _generate_code_hash(custom_component._code, module_name) - if code_hash: - frontend_node.metadata["code_hash"] = code_hash - except Exception as exc: # noqa: BLE001 - logger.debug(f"Error generating code hash for {custom_component.__class__.__name__}", exc_info=exc) + frontend_node = build_component_metadata( + frontend_node, custom_component, module_name, custom_component.__class__.__name__ + ) return frontend_node.to_dict(keep_name=False), custom_instance except Exception as exc: diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json index 1b0332889..dc0761e36 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompt Chaining.json @@ -363,6 +363,15 @@ "lf_version": "1.5.0", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -664,6 +673,23 @@ "lf_version": "1.5.0", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json index 1a7089acb..9c68a6283 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Basic Prompting.json @@ -118,6 +118,15 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -616,6 +625,23 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json index e2b67f1fa..019bf19aa 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Blog Writer.json @@ -353,6 +353,15 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], @@ -469,6 +478,23 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], @@ -792,6 +818,15 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "556209520650", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.processing.parser.ParserComponent" }, "minimized": false, @@ -979,6 +1014,27 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "252132357639", + "dependencies": { + "dependencies": [ + { + "name": "requests", + "version": "2.32.4" + }, + { + "name": "bs4", + "version": "4.12.3" + }, + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.data.url.URLComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json b/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json index ce52b8b6b..01dcf6bf4 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Custom Component Generator.json @@ -238,6 +238,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "464cc8b8fdd2", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.helpers.memory.MemoryComponent" }, "output_types": [], @@ -1926,6 +1935,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -2243,6 +2261,23 @@ "legacy": false, "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json b/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json index 3217d3503..0faca6e1a 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Document Q&A.json @@ -148,6 +148,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -443,6 +452,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json b/src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json index a62cbf4d6..e381dd63b 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Financial Report Parser.json @@ -151,6 +151,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -466,6 +483,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -1294,6 +1320,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "ad2a6f4552c0", + "dependencies": { + "dependencies": [ + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "trustcall", + "version": "0.0.39" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.processing.structured_output.StructuredOutputComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Hybrid Search RAG.json b/src/backend/base/langflow/initial_setup/starter_projects/Hybrid Search RAG.json index ed7435015..fa5621569 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Hybrid Search RAG.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Hybrid Search RAG.json @@ -206,6 +206,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -516,6 +525,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "556209520650", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.processing.parser.ParserComponent" }, "minimized": false, @@ -698,6 +716,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1003,6 +1038,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "556209520650", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.processing.parser.ParserComponent" }, "minimized": false, @@ -1199,6 +1243,27 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "23fbe9daca09", + "dependencies": { + "dependencies": [ + { + "name": "astrapy", + "version": "2.0.1" + }, + { + "name": "langchain_astradb", + "version": "0.6.0" + }, + { + "name": "langchain_core", + "version": "0.3.72" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.datastax.astradb.AstraDBVectorStoreComponent" }, "minimized": false, @@ -2583,6 +2648,23 @@ "legacy": false, "metadata": { "code_hash": "ad2a6f4552c0", + "dependencies": { + "dependencies": [ + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "trustcall", + "version": "0.0.39" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.processing.structured_output.StructuredOutputComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json b/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json index 1c7fe85df..82f9b703c 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Image Sentiment Analysis.json @@ -235,6 +235,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -543,6 +552,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], @@ -1010,6 +1036,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "ad2a6f4552c0", + "dependencies": { + "dependencies": [ + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "trustcall", + "version": "0.0.39" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.processing.structured_output.StructuredOutputComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json index 547a7868c..487a1b246 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Instagram Copywriter.json @@ -318,6 +318,15 @@ "lf_version": "1.1.1", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -790,6 +799,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], @@ -1065,6 +1083,23 @@ "legacy": false, "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], @@ -1588,6 +1623,19 @@ "legacy": false, "metadata": { "code_hash": "4c76fb76d395", + "dependencies": { + "dependencies": [ + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.tavily.tavily_search.TavilySearchComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json b/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json index c26627a8f..0ab3acd5d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Invoice Summarizer.json @@ -306,6 +306,23 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -670,6 +687,19 @@ "legacy": false, "metadata": { "code_hash": "57d868cb067b", + "dependencies": { + "dependencies": [ + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.needle.needle.NeedleComponent" }, "minimized": false, @@ -878,6 +908,15 @@ "legacy": false, "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Ingestion.json b/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Ingestion.json index dc0bceffb..4f7194c90 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Ingestion.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Ingestion.json @@ -89,6 +89,19 @@ "lf_version": "1.5.0.post1", "metadata": { "code_hash": "dbf2e9d2319d", + "dependencies": { + "dependencies": [ + { + "name": "langchain_text_splitters", + "version": "0.3.8" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.processing.split_text.SplitTextComponent" }, "minimized": false, @@ -340,6 +353,27 @@ "lf_version": "1.5.0.post1", "metadata": { "code_hash": "252132357639", + "dependencies": { + "dependencies": [ + { + "name": "requests", + "version": "2.32.4" + }, + { + "name": "bs4", + "version": "4.12.3" + }, + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.data.url.URLComponent" }, "minimized": false, @@ -703,6 +737,43 @@ "legacy": false, "metadata": { "code_hash": "6c62063f2c09", + "dependencies": { + "dependencies": [ + { + "name": "pandas", + "version": "2.2.3" + }, + { + "name": "cryptography", + "version": "43.0.3" + }, + { + "name": "langchain_chroma", + "version": "0.1.4" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "langflow", + "version": null + }, + { + "name": "langchain_openai", + "version": "0.3.23" + }, + { + "name": "langchain_huggingface", + "version": "0.3.1" + }, + { + "name": "langchain_cohere", + "version": "0.3.3" + } + ], + "total_dependencies": 8 + }, "module": "langflow.components.data.kb_ingest.KBIngestionComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Retrieval.json b/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Retrieval.json index c83495376..c27915b89 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Retrieval.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Knowledge Retrieval.json @@ -109,6 +109,15 @@ "lf_version": "1.5.0.post1", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "minimized": false, @@ -226,6 +235,23 @@ "lf_version": "1.5.0.post1", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -533,6 +559,43 @@ "legacy": false, "metadata": { "code_hash": "6fcf86be1aca", + "dependencies": { + "dependencies": [ + { + "name": "cryptography", + "version": "43.0.3" + }, + { + "name": "langchain_chroma", + "version": "0.1.4" + }, + { + "name": "loguru", + "version": "0.7.3" + }, + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "langflow", + "version": null + }, + { + "name": "langchain_openai", + "version": "0.3.23" + }, + { + "name": "langchain_huggingface", + "version": "0.3.1" + }, + { + "name": "langchain_cohere", + "version": "0.3.3" + } + ], + "total_dependencies": 8 + }, "module": "langflow.components.data.kb_retrieval.KBRetrievalComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json index ae1a66631..4198ea237 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Market Research.json @@ -197,6 +197,15 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -498,6 +507,23 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], @@ -840,6 +866,23 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "ad2a6f4552c0", + "dependencies": { + "dependencies": [ + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "trustcall", + "version": "0.0.39" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.processing.structured_output.StructuredOutputComponent" }, "minimized": false, @@ -1191,6 +1234,19 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "4c76fb76d395", + "dependencies": { + "dependencies": [ + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.tavily.tavily_search.TavilySearchComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json b/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json index cdd8fabe3..070d30f80 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Meeting Summary.json @@ -315,6 +315,19 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "3e67a5940263", + "dependencies": { + "dependencies": [ + { + "name": "assemblyai", + "version": "0.35.1" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.assemblyai.assemblyai_poll_transcript.AssemblyAITranscriptionJobPoller" }, "minimized": false, @@ -627,6 +640,23 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -932,6 +962,23 @@ "lf_version": "1.1.1", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1237,6 +1284,23 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1719,6 +1783,15 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "464cc8b8fdd2", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.helpers.memory.MemoryComponent" }, "minimized": false, @@ -2049,6 +2122,15 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -2467,6 +2549,19 @@ "legacy": false, "metadata": { "code_hash": "03d20eaf49f4", + "dependencies": { + "dependencies": [ + { + "name": "assemblyai", + "version": "0.35.1" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.assemblyai.assemblyai_start_transcript.AssemblyAITranscriptionJobCreator" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json index aaa0b8f57..f78ddd28d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Memory Chatbot.json @@ -149,6 +149,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -458,6 +467,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], @@ -960,6 +986,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "464cc8b8fdd2", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.helpers.memory.MemoryComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json index 7eb6ef72c..aaf148e12 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/News Aggregator.json @@ -206,6 +206,19 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "ab828f4cdff2", + "dependencies": { + "dependencies": [ + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.agentql.agentql_api.AgentQL" }, "minimized": false, @@ -562,6 +575,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -904,6 +926,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1209,6 +1248,27 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "1bcc6faaaa62", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "pandas", + "version": "2.2.3" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.processing.save_file.SaveToFileComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json b/src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json index 6f9813090..36925b00e 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Nvidia Remix.json @@ -233,6 +233,15 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -549,6 +558,23 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1890,6 +1916,19 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "93faf11517da", + "dependencies": { + "dependencies": [ + { + "name": "langchain_openai", + "version": "0.3.23" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.models.embedding_model.EmbeddingModelComponent" }, "minimized": false, @@ -2183,6 +2222,19 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "ed38680af3a6", + "dependencies": { + "dependencies": [ + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.FAISS.faiss.FaissVectorStoreComponent" }, "minimized": false, @@ -2519,6 +2571,19 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "bd0c4250c82c", + "dependencies": { + "dependencies": [ + { + "name": "langchain_core", + "version": "0.3.72" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.agents.mcp_component.MCPToolsComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json index 4b73fa372..dd67a71fb 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Pokédex Agent.json @@ -113,6 +113,15 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -430,6 +439,23 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -832,6 +858,27 @@ "legacy": false, "metadata": { "code_hash": "a648ad26f226", + "dependencies": { + "dependencies": [ + { + "name": "aiofiles", + "version": "24.1.0" + }, + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "validators", + "version": "0.34.0" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.data.api_request.APIRequestComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json b/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json index 50b759233..5a3c3c4cb 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json @@ -193,6 +193,15 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "minimized": false, @@ -312,6 +321,23 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -767,6 +793,23 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "ad2a6f4552c0", + "dependencies": { + "dependencies": [ + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "trustcall", + "version": "0.0.39" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.processing.structured_output.StructuredOutputComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json index 5b9106bee..257316984 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Price Deal Finder.json @@ -138,6 +138,15 @@ "lf_version": "1.3.2", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -454,6 +463,23 @@ "lf_version": "1.3.2", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -768,6 +794,19 @@ "lf_version": "1.3.2", "metadata": { "code_hash": "4c76fb76d395", + "dependencies": { + "dependencies": [ + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.tavily.tavily_search.TavilySearchComponent" }, "minimized": false, @@ -1169,6 +1208,19 @@ "lf_version": "1.3.2", "metadata": { "code_hash": "ab828f4cdff2", + "dependencies": { + "dependencies": [ + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.agentql.agentql_api.AgentQL" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json index 20b7fb904..0038bdca0 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Research Agent.json @@ -478,6 +478,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -1259,6 +1268,19 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "4c76fb76d395", + "dependencies": { + "dependencies": [ + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.tavily.tavily_search.TavilySearchComponent" }, "minimized": false, @@ -1660,6 +1682,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json b/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json index 235dda0ec..d26d7e146 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Research Translation Loop.json @@ -229,6 +229,19 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "b61405ff011f", + "dependencies": { + "dependencies": [ + { + "name": "defusedxml", + "version": "0.7.1" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.arxiv.arxiv.ArXivComponent" }, "minimized": false, @@ -390,6 +403,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -701,6 +731,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -1038,6 +1077,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "556209520650", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.processing.parser.ParserComponent" }, "minimized": false, @@ -1213,6 +1261,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "5b234f78c942", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.logic.loop.LoopComponent" }, "minimized": false, @@ -1626,6 +1683,15 @@ "legacy": false, "metadata": { "code_hash": "38e56a852063", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.processing.converter.TypeConverterComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json b/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json index 3e4232e42..840652f0d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/SEO Keyword Generator.json @@ -563,6 +563,23 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], diff --git a/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json b/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json index 21964516c..2212c9be8 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/SaaS Pricing.json @@ -371,6 +371,23 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -716,6 +733,15 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "3139fe9e04a5", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.helpers.calculator_core.CalculatorComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json index 1e8db8d87..545e15310 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Search agent.json @@ -104,6 +104,19 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "99b8b89dc4ca", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + }, + { + "name": "scrapegraph_py", + "version": "1.12.0" + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.scrapegraph.scrapegraph_search_api.ScrapeGraphSearchApi" }, "minimized": false, @@ -278,6 +291,15 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -592,6 +614,23 @@ "lf_version": "1.1.5", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, 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 f8b5da348..3894ab506 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 @@ -1911,6 +1911,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -2801,6 +2810,27 @@ "legacy": false, "metadata": { "code_hash": "6e61ed5ad81b", + "dependencies": { + "dependencies": [ + { + "name": "yfinance", + "version": "0.2.50" + }, + { + "name": "langchain_core", + "version": "0.3.72" + }, + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.yahoosearch.yahoo.YfinanceComponent" }, "minimized": false, @@ -3015,6 +3045,15 @@ "legacy": false, "metadata": { "code_hash": "3139fe9e04a5", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.helpers.calculator_core.CalculatorComponent" }, "minimized": false, @@ -3172,6 +3211,19 @@ "legacy": false, "metadata": { "code_hash": "4c76fb76d395", + "dependencies": { + "dependencies": [ + { + "name": "httpx", + "version": "0.27.2" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.tavily.tavily_search.TavilySearchComponent" }, "minimized": false, @@ -3572,6 +3624,23 @@ "legacy": false, "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json index 270338d24..37a35708f 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Simple Agent.json @@ -192,6 +192,15 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "3139fe9e04a5", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.helpers.calculator_core.CalculatorComponent" }, "minimized": false, @@ -350,6 +359,15 @@ "legacy": false, "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -668,6 +686,23 @@ "legacy": false, "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1526,6 +1561,27 @@ "legacy": false, "metadata": { "code_hash": "252132357639", + "dependencies": { + "dependencies": [ + { + "name": "requests", + "version": "2.32.4" + }, + { + "name": "bs4", + "version": "4.12.3" + }, + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.data.url.URLComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json b/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json index c032d24f6..98e8f5f36 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Social Media Agent.json @@ -145,6 +145,31 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "233d7ef687d5", + "dependencies": { + "dependencies": [ + { + "name": "apify_client", + "version": "1.11.0" + }, + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langchain_core", + "version": "0.3.72" + }, + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 5 + }, "module": "langflow.components.apify.apify_actor.ApifyActorsComponent" }, "minimized": false, @@ -351,6 +376,31 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "233d7ef687d5", + "dependencies": { + "dependencies": [ + { + "name": "apify_client", + "version": "1.11.0" + }, + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langchain_core", + "version": "0.3.72" + }, + { + "name": "pydantic", + "version": "2.10.6" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 5 + }, "module": "langflow.components.apify.apify_actor.ApifyActorsComponent" }, "minimized": false, @@ -644,6 +694,15 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -959,6 +1018,23 @@ "lf_version": "1.4.2", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json b/src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json index cb31022ca..b9ba7aed0 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Text Sentiment Analysis.json @@ -714,6 +714,23 @@ "legacy": false, "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1025,6 +1042,23 @@ "legacy": false, "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json index e522f90df..a492b8d0d 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Travel Planning Agents.json @@ -229,6 +229,15 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -530,6 +539,23 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], @@ -1277,6 +1303,15 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "3139fe9e04a5", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.helpers.calculator_core.CalculatorComponent" }, "minimized": false, @@ -1435,6 +1470,19 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "c561e416205b", + "dependencies": { + "dependencies": [ + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.searchapi.search.SearchComponent" }, "minimized": false, diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json b/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json index d96cc7871..d933f670f 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Twitter Thread Generator.json @@ -284,6 +284,15 @@ "legacy": false, "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, @@ -596,6 +605,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], @@ -714,6 +732,23 @@ "legacy": false, "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1023,6 +1058,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], @@ -1131,6 +1175,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], @@ -1239,6 +1292,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], @@ -1347,6 +1409,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], @@ -1455,6 +1526,15 @@ "lf_version": "1.0.19.post2", "metadata": { "code_hash": "efdcba3771af", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.text.TextInputComponent" }, "output_types": [], diff --git a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json index 45dddf829..5a33dbd79 100644 --- a/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json +++ b/src/backend/base/langflow/initial_setup/starter_projects/Vector Store RAG.json @@ -321,6 +321,15 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "output_types": [], @@ -795,6 +804,19 @@ "lf_version": "1.1.1", "metadata": { "code_hash": "dbf2e9d2319d", + "dependencies": { + "dependencies": [ + { + "name": "langchain_text_splitters", + "version": "0.3.8" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.processing.split_text.SplitTextComponent" }, "output_types": [], @@ -1084,6 +1106,23 @@ "lf_version": "1.1.1", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "output_types": [], @@ -1401,6 +1440,19 @@ "lf_version": "1.2.0", "metadata": { "code_hash": "2691dee277c9", + "dependencies": { + "dependencies": [ + { + "name": "langchain_openai", + "version": "0.3.23" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.openai.openai.OpenAIEmbeddingsComponent" }, "output_types": [], @@ -1937,6 +1989,19 @@ "lf_version": "1.1.1", "metadata": { "code_hash": "2691dee277c9", + "dependencies": { + "dependencies": [ + { + "name": "langchain_openai", + "version": "0.3.23" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 2 + }, "module": "langflow.components.openai.openai.OpenAIEmbeddingsComponent" }, "output_types": [], @@ -2710,6 +2775,27 @@ "legacy": false, "metadata": { "code_hash": "23fbe9daca09", + "dependencies": { + "dependencies": [ + { + "name": "astrapy", + "version": "2.0.1" + }, + { + "name": "langchain_astradb", + "version": "0.6.0" + }, + { + "name": "langchain_core", + "version": "0.3.72" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.datastax.astradb.AstraDBVectorStoreComponent" }, "minimized": false, @@ -3486,6 +3572,27 @@ "legacy": false, "metadata": { "code_hash": "23fbe9daca09", + "dependencies": { + "dependencies": [ + { + "name": "astrapy", + "version": "2.0.1" + }, + { + "name": "langchain_astradb", + "version": "0.6.0" + }, + { + "name": "langchain_core", + "version": "0.3.72" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.datastax.astradb.AstraDBVectorStoreComponent" }, "minimized": false, 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 3c3ede037..86ec392e5 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 @@ -286,6 +286,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "ee50d5005321", + "dependencies": { + "dependencies": [ + { + "name": "toml", + "version": "0.10.2" + }, + { + "name": "langflow", + "version": null + }, + { + "name": "langchain_core", + "version": "0.3.72" + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.processing.batch_run.BatchRunComponent" }, "minimized": false, @@ -504,6 +521,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "aeda2975f4aa", + "dependencies": { + "dependencies": [ + { + "name": "pandas", + "version": "2.2.3" + }, + { + "name": "googleapiclient", + "version": "2.154.0" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.youtube.comments.YouTubeCommentsComponent" }, "minimized": false, @@ -1440,6 +1474,23 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "6f74e04e39d5", + "dependencies": { + "dependencies": [ + { + "name": "orjson", + "version": "3.10.15" + }, + { + "name": "fastapi", + "version": "0.115.13" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 3 + }, "module": "langflow.components.input_output.chat_output.ChatOutput" }, "minimized": true, @@ -1751,6 +1802,27 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "c9f0262ff0b6", + "dependencies": { + "dependencies": [ + { + "name": "pandas", + "version": "2.2.3" + }, + { + "name": "youtube_transcript_api", + "version": "0.6.3" + }, + { + "name": "langchain_community", + "version": "0.3.21" + }, + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 4 + }, "module": "langflow.components.youtube.youtube_transcripts.YouTubeTranscriptsComponent" }, "minimized": false, @@ -2501,6 +2573,15 @@ "lf_version": "1.4.3", "metadata": { "code_hash": "192913db3453", + "dependencies": { + "dependencies": [ + { + "name": "langflow", + "version": null + } + ], + "total_dependencies": 1 + }, "module": "langflow.components.input_output.chat.ChatInput" }, "minimized": true, diff --git a/src/backend/tests/unit/custom/test_utils_metadata.py b/src/backend/tests/unit/custom/test_utils_metadata.py index 015e9b1b0..7812dc3eb 100644 --- a/src/backend/tests/unit/custom/test_utils_metadata.py +++ b/src/backend/tests/unit/custom/test_utils_metadata.py @@ -3,7 +3,11 @@ from unittest.mock import Mock, patch import pytest -from langflow.custom.utils import _generate_code_hash +from langflow.custom.utils import ( + _generate_code_hash, + build_component_metadata, + build_custom_component_template_from_inputs, +) class TestCodeHashGeneration: @@ -141,21 +145,373 @@ class TestMetadataInTemplateBuilders: assert len(result) == 12 assert all(c in "0123456789abcdef" for c in result) - @patch("langflow.custom.utils.ComponentFrontendNode") - def test_build_from_inputs_without_module_generates_default(self, mock_frontend_class): - """Test that build_custom_component_template_from_inputs generates default module when module_name is None.""" + +class TestDependencyAnalyzer: + """Test dependency analysis functionality.""" + + def test_top_level_basic(self): + """Test extracting top level package name.""" + from langflow.custom.dependency_analyzer import _top_level + + assert _top_level("numpy") == "numpy" + assert _top_level("numpy.array") == "numpy" + assert _top_level("requests.adapters.HTTPAdapter") == "requests" + + def test_is_relative(self): + """Test relative import detection.""" + from langflow.custom.dependency_analyzer import _is_relative + + assert _is_relative(".module") is True + assert _is_relative("..parent") is True + assert _is_relative("...grandparent") is True + assert _is_relative("module") is False + assert _is_relative(None) is False + + def test_analyze_dependencies_basic(self): + """Test basic dependency analysis.""" + from langflow.custom.dependency_analyzer import analyze_dependencies + + code = """ +import os +import sys +from typing import List +import numpy as np +from requests import get +""" + + deps = analyze_dependencies(code, resolve_versions=False) + + # Should find external dependencies only (stdlib imports filtered out) + assert len(deps) == 2 + + # Check external dependencies + dep_names = [d["name"] for d in deps] + assert "numpy" in dep_names + assert "requests" in dep_names + + # Stdlib imports should be filtered out + assert "os" not in dep_names + assert "sys" not in dep_names + assert "typing" not in dep_names + + def test_analyze_dependencies_optional_detection(self): + """Test that all dependencies are treated as required (no optional detection).""" + from langflow.custom.dependency_analyzer import analyze_dependencies + + code = """ +import os +try: + import optional_package + HAS_OPTIONAL = True +except ImportError: + HAS_OPTIONAL = False + +try: + from another_optional import something +except ImportError: + pass # This is now treated as a regular dependency +""" + + deps = analyze_dependencies(code, resolve_versions=False) + + # Should find external dependencies only (stdlib imports filtered out) + assert len(deps) == 2 # optional_package, another_optional + dep_names = [d["name"] for d in deps] + assert "optional_package" in dep_names + assert "another_optional" in dep_names + + # Stdlib imports should be filtered out + assert "os" not in dep_names + + def test_analyze_component_dependencies(self): + """Test component-specific dependency analysis.""" + from langflow.custom.dependency_analyzer import analyze_component_dependencies + + component_code = """ +import os +import sys +from typing import Dict, List +from langflow.custom import CustomComponent +import numpy as np + +class TestComponent(CustomComponent): + def build(self): + return {"test": "value"} +""" + + result = analyze_component_dependencies(component_code) + + # Check structure + assert "total_dependencies" in result + assert "dependencies" in result + + # Should have some dependencies (only external dependencies) + assert result["total_dependencies"] > 0 + + # Should have dependencies list + assert isinstance(result["dependencies"], list) + + # Verify no duplicate packages in dependencies + package_names = [pkg["name"] for pkg in result["dependencies"]] + assert len(package_names) == len(set(package_names)), "No duplicate packages should exist" + + def test_analyze_component_dependencies_error_handling(self): + """Test error handling in component dependency analysis.""" + from langflow.custom.dependency_analyzer import analyze_component_dependencies + + # Test with invalid Python code + invalid_code = "import os\nthis is not valid python syntax!!!" + + result = analyze_component_dependencies(invalid_code) + + # Should return minimal info on error + assert result["total_dependencies"] == 0 + assert result["dependencies"] == [] + + def test_dependency_info_dataclass(self): + """Test DependencyInfo dataclass creation.""" + from langflow.custom.dependency_analyzer import DependencyInfo + + dep = DependencyInfo( + name="numpy", + version="1.21.0", + is_local=False, + ) + + assert dep.name == "numpy" + assert dep.version == "1.21.0" + assert not dep.is_local + + def test_no_optional_dependency_classification(self): + """Test that the simplified analyzer doesn't classify any dependencies as optional.""" + from langflow.custom.dependency_analyzer import analyze_dependencies + + # Code with various import patterns that previously might have been considered optional + code = """ +import os +try: + import package_a + HAS_A = True +except ImportError: + HAS_A = False + +try: + import package_b +except ImportError: + pass + +try: + from package_c import something +except (ImportError, ModuleNotFoundError): + something = None +""" + deps = analyze_dependencies(code, resolve_versions=False) + + # Should find external dependencies only (stdlib filtered out) + dep_names = [d["name"] for d in deps] + assert "package_a" in dep_names + assert "package_b" in dep_names + assert "package_c" in dep_names + + # Stdlib imports should be filtered out + assert "os" not in dep_names + + # All found dependencies should be external (not local) + for dep in deps: + assert not dep["is_local"], f"Dependency {dep['name']} should not be local" + + +class TestMetadataWithDependencies: + """Test metadata functionality including dependencies.""" + + def test_build_component_metadata_includes_dependencies(self): + """Test that build_component_metadata includes dependency analysis.""" + + def test_build_from_inputs_without_module_generates_default(self): + """Test that build_component_metadata includes dependency analysis results.""" from langflow.custom.custom_component.component import Component - from langflow.custom.utils import build_custom_component_template_from_inputs # Setup mock frontend node mock_frontend = Mock() mock_frontend.metadata = {} + + # Create test component with real code + test_component = Mock(spec=Component) + test_component._code = """ +import os +import sys +from typing import List + +class TestComponent: + def build(self): + return {"test": "value"} +""" + + # Call the function + build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent") + + # Verify metadata was added + assert "module" in mock_frontend.metadata + assert "code_hash" in mock_frontend.metadata + assert "dependencies" in mock_frontend.metadata + + # Verify dependency analysis results + dep_info = mock_frontend.metadata["dependencies"] + # Only external dependencies are tracked now (stdlib filtered out) + assert dep_info["total_dependencies"] == 0 # No external deps in this test code + assert "dependencies" in dep_info + assert isinstance(dep_info["dependencies"], list) + + def test_build_component_metadata_handles_analysis_error(self): + """Test that build_component_metadata handles dependency analysis errors gracefully.""" + from langflow.custom.custom_component.component import Component + + # Setup mock frontend node + mock_frontend = Mock() + mock_frontend.metadata = {} + + # Create test component with invalid Python code + test_component = Mock(spec=Component) + test_component._code = "import os\nthis is not valid python syntax!!!" + + # Call the function - should not raise exception + build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent") + + # Should not raise exception and should set minimal dependency info + assert "dependencies" in mock_frontend.metadata + dep_info = mock_frontend.metadata["dependencies"] + assert dep_info["total_dependencies"] == 0 + assert dep_info["dependencies"] == [] + + def test_build_component_metadata_with_external_dependencies(self): + """Test dependency analysis with external packages.""" + from langflow.custom.custom_component.component import Component + + # Setup mock frontend node + mock_frontend = Mock() + mock_frontend.metadata = {} + + # Create test component with external dependencies + test_component = Mock(spec=Component) + test_component._code = """ +import os +from langflow.custom import CustomComponent + +class TestComponent(CustomComponent): + def build(self): + return {"test": "value"} +""" + + # Call the function + build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent") + + # Verify dependency analysis results + dep_info = mock_frontend.metadata["dependencies"] + assert dep_info["total_dependencies"] == 1 # Only langflow (os is stdlib, filtered out) + + # Check for dependencies + package_names = [pkg["name"] for pkg in dep_info["dependencies"]] + assert "langflow" in package_names # langflow should be detected as external + assert "os" not in package_names # os is stdlib, should be filtered out + + def test_build_component_metadata_with_optional_dependencies(self): + """Test dependency analysis with optional dependencies.""" + from langflow.custom.custom_component.component import Component + + # Setup mock frontend node + mock_frontend = Mock() + mock_frontend.metadata = {} + + # Create test component with optional dependencies + test_component = Mock(spec=Component) + test_component._code = """ +import os +try: + import some_optional_package + HAS_OPTIONAL = True +except ImportError: + HAS_OPTIONAL = False + +class TestComponent: + def build(self): + return {"test": "value"} +""" + + # Call the function + build_component_metadata(mock_frontend, test_component, "test.module", "TestComponent") + + # Verify dependency analysis results + dep_info = mock_frontend.metadata["dependencies"] + assert dep_info["total_dependencies"] == 1 # Only some_optional_package (os is stdlib, filtered out) + + # Verify the dependencies are found + package_names = [pkg["name"] for pkg in dep_info["dependencies"]] + assert "some_optional_package" in package_names + assert "os" not in package_names # os is stdlib, should be filtered out + + def test_build_component_metadata_with_real_component(self): + """Test dependency analysis with a real component.""" + from langflow.custom.custom_component.component import Component + from langflow.custom.utils import build_component_metadata + + # Setup mock frontend node + mock_frontend = Mock() + mock_frontend.metadata = {} + + # Use real component code based on LMStudio component + real_component_code = """from typing import Any +from urllib.parse import urljoin + +import httpx +from langchain_openai import ChatOpenAI + +from langflow.base.models.model import LCModelComponent +from langflow.field_typing import LanguageModel + +class LMStudioModelComponent(LCModelComponent): + display_name = "LM Studio" + description = "Generate text using LM Studio Local LLMs." + icon = "LMStudio" + name = "LMStudioModel" + + def build(self): + return {"test": "value"} +""" + + # Create test component + test_component = Mock(spec=Component) + test_component._code = real_component_code + + # Call the function + build_component_metadata( + mock_frontend, test_component, "langflow.components.lmstudio", "LMStudioModelComponent" + ) + + # Verify metadata was added + assert "module" in mock_frontend.metadata + assert "code_hash" in mock_frontend.metadata + assert "dependencies" in mock_frontend.metadata + + # Verify dependency analysis results + dep_info = mock_frontend.metadata["dependencies"] + assert dep_info["total_dependencies"] > 0 + + # Check that external dependencies are found (stdlib filtered out) + package_names = [pkg["name"] for pkg in dep_info["dependencies"]] + + # External packages should be found + assert "httpx" in package_names # external + assert "langchain_openai" in package_names # external + assert "langflow" in package_names # project dependency + + # Stdlib imports should be filtered out + assert "typing" not in package_names + assert "urllib" not in package_names mock_frontend.outputs = [] mock_frontend.to_dict = Mock(return_value={"test": "data"}) mock_frontend.validate_component = Mock() mock_frontend.set_base_classes_from_outputs = Mock() mock_frontend.display_name = "My Test Component" - mock_frontend_class.from_inputs.return_value = mock_frontend # Create test component test_component = Mock(spec=Component) @@ -176,7 +532,7 @@ class TestMetadataInTemplateBuilders: patch("langflow.custom.utils.reorder_fields"), ): # Call the function without module_name - template, _ = build_custom_component_template_from_inputs(test_component, module_name=None) + _, _ = build_custom_component_template_from_inputs(test_component, module_name=None) # Verify metadata was added with generated module name assert "module" in mock_frontend.metadata