lfx-nightly 0.2.0.dev0__py3-none-any.whl → 0.2.0.dev41__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (196) hide show
  1. lfx/_assets/component_index.json +1 -1
  2. lfx/base/agents/agent.py +21 -4
  3. lfx/base/agents/altk_base_agent.py +393 -0
  4. lfx/base/agents/altk_tool_wrappers.py +565 -0
  5. lfx/base/agents/events.py +2 -1
  6. lfx/base/composio/composio_base.py +159 -224
  7. lfx/base/data/base_file.py +97 -20
  8. lfx/base/data/docling_utils.py +61 -10
  9. lfx/base/data/storage_utils.py +301 -0
  10. lfx/base/data/utils.py +178 -14
  11. lfx/base/mcp/util.py +2 -2
  12. lfx/base/models/anthropic_constants.py +21 -12
  13. lfx/base/models/groq_constants.py +74 -58
  14. lfx/base/models/groq_model_discovery.py +265 -0
  15. lfx/base/models/model.py +1 -1
  16. lfx/base/models/model_utils.py +100 -0
  17. lfx/base/models/openai_constants.py +7 -0
  18. lfx/base/models/watsonx_constants.py +32 -8
  19. lfx/base/tools/run_flow.py +601 -129
  20. lfx/cli/commands.py +9 -4
  21. lfx/cli/common.py +2 -2
  22. lfx/cli/run.py +1 -1
  23. lfx/cli/script_loader.py +53 -11
  24. lfx/components/Notion/create_page.py +1 -1
  25. lfx/components/Notion/list_database_properties.py +1 -1
  26. lfx/components/Notion/list_pages.py +1 -1
  27. lfx/components/Notion/list_users.py +1 -1
  28. lfx/components/Notion/page_content_viewer.py +1 -1
  29. lfx/components/Notion/search.py +1 -1
  30. lfx/components/Notion/update_page_property.py +1 -1
  31. lfx/components/__init__.py +19 -5
  32. lfx/components/{agents → altk}/__init__.py +5 -9
  33. lfx/components/altk/altk_agent.py +193 -0
  34. lfx/components/apify/apify_actor.py +1 -1
  35. lfx/components/composio/__init__.py +70 -18
  36. lfx/components/composio/apollo_composio.py +11 -0
  37. lfx/components/composio/bitbucket_composio.py +11 -0
  38. lfx/components/composio/canva_composio.py +11 -0
  39. lfx/components/composio/coda_composio.py +11 -0
  40. lfx/components/composio/composio_api.py +10 -0
  41. lfx/components/composio/discord_composio.py +1 -1
  42. lfx/components/composio/elevenlabs_composio.py +11 -0
  43. lfx/components/composio/exa_composio.py +11 -0
  44. lfx/components/composio/firecrawl_composio.py +11 -0
  45. lfx/components/composio/fireflies_composio.py +11 -0
  46. lfx/components/composio/gmail_composio.py +1 -1
  47. lfx/components/composio/googlebigquery_composio.py +11 -0
  48. lfx/components/composio/googlecalendar_composio.py +1 -1
  49. lfx/components/composio/googledocs_composio.py +1 -1
  50. lfx/components/composio/googlemeet_composio.py +1 -1
  51. lfx/components/composio/googlesheets_composio.py +1 -1
  52. lfx/components/composio/googletasks_composio.py +1 -1
  53. lfx/components/composio/heygen_composio.py +11 -0
  54. lfx/components/composio/mem0_composio.py +11 -0
  55. lfx/components/composio/peopledatalabs_composio.py +11 -0
  56. lfx/components/composio/perplexityai_composio.py +11 -0
  57. lfx/components/composio/serpapi_composio.py +11 -0
  58. lfx/components/composio/slack_composio.py +3 -574
  59. lfx/components/composio/slackbot_composio.py +1 -1
  60. lfx/components/composio/snowflake_composio.py +11 -0
  61. lfx/components/composio/tavily_composio.py +11 -0
  62. lfx/components/composio/youtube_composio.py +2 -2
  63. lfx/components/cuga/__init__.py +34 -0
  64. lfx/components/cuga/cuga_agent.py +730 -0
  65. lfx/components/data/__init__.py +78 -28
  66. lfx/components/data_source/__init__.py +58 -0
  67. lfx/components/{data → data_source}/api_request.py +26 -3
  68. lfx/components/{data → data_source}/csv_to_data.py +15 -10
  69. lfx/components/{data → data_source}/json_to_data.py +15 -8
  70. lfx/components/{data → data_source}/news_search.py +1 -1
  71. lfx/components/{data → data_source}/rss.py +1 -1
  72. lfx/components/{data → data_source}/sql_executor.py +1 -1
  73. lfx/components/{data → data_source}/url.py +1 -1
  74. lfx/components/{data → data_source}/web_search.py +1 -1
  75. lfx/components/datastax/astradb_cql.py +1 -1
  76. lfx/components/datastax/astradb_graph.py +1 -1
  77. lfx/components/datastax/astradb_tool.py +1 -1
  78. lfx/components/datastax/astradb_vectorstore.py +1 -1
  79. lfx/components/datastax/hcd.py +1 -1
  80. lfx/components/deactivated/json_document_builder.py +1 -1
  81. lfx/components/docling/__init__.py +0 -3
  82. lfx/components/docling/chunk_docling_document.py +3 -1
  83. lfx/components/docling/export_docling_document.py +3 -1
  84. lfx/components/elastic/elasticsearch.py +1 -1
  85. lfx/components/files_and_knowledge/__init__.py +47 -0
  86. lfx/components/{data → files_and_knowledge}/directory.py +1 -1
  87. lfx/components/{data → files_and_knowledge}/file.py +304 -24
  88. lfx/components/{knowledge_bases → files_and_knowledge}/retrieval.py +2 -2
  89. lfx/components/{data → files_and_knowledge}/save_file.py +218 -31
  90. lfx/components/flow_controls/__init__.py +58 -0
  91. lfx/components/{logic → flow_controls}/conditional_router.py +1 -1
  92. lfx/components/{logic → flow_controls}/loop.py +43 -9
  93. lfx/components/flow_controls/run_flow.py +108 -0
  94. lfx/components/glean/glean_search_api.py +1 -1
  95. lfx/components/groq/groq.py +35 -28
  96. lfx/components/helpers/__init__.py +102 -0
  97. lfx/components/ibm/watsonx.py +7 -1
  98. lfx/components/input_output/__init__.py +3 -1
  99. lfx/components/input_output/chat.py +4 -3
  100. lfx/components/input_output/chat_output.py +10 -4
  101. lfx/components/input_output/text.py +1 -1
  102. lfx/components/input_output/text_output.py +1 -1
  103. lfx/components/{data → input_output}/webhook.py +1 -1
  104. lfx/components/knowledge_bases/__init__.py +59 -4
  105. lfx/components/langchain_utilities/character.py +1 -1
  106. lfx/components/langchain_utilities/csv_agent.py +84 -16
  107. lfx/components/langchain_utilities/json_agent.py +67 -12
  108. lfx/components/langchain_utilities/language_recursive.py +1 -1
  109. lfx/components/llm_operations/__init__.py +46 -0
  110. lfx/components/{processing → llm_operations}/batch_run.py +17 -8
  111. lfx/components/{processing → llm_operations}/lambda_filter.py +1 -1
  112. lfx/components/{logic → llm_operations}/llm_conditional_router.py +1 -1
  113. lfx/components/{processing/llm_router.py → llm_operations/llm_selector.py} +3 -3
  114. lfx/components/{processing → llm_operations}/structured_output.py +1 -1
  115. lfx/components/logic/__init__.py +126 -0
  116. lfx/components/mem0/mem0_chat_memory.py +11 -0
  117. lfx/components/models/__init__.py +64 -9
  118. lfx/components/models_and_agents/__init__.py +49 -0
  119. lfx/components/{agents → models_and_agents}/agent.py +6 -4
  120. lfx/components/models_and_agents/embedding_model.py +353 -0
  121. lfx/components/models_and_agents/language_model.py +398 -0
  122. lfx/components/{agents → models_and_agents}/mcp_component.py +53 -44
  123. lfx/components/{helpers → models_and_agents}/memory.py +1 -1
  124. lfx/components/nvidia/system_assist.py +1 -1
  125. lfx/components/olivya/olivya.py +1 -1
  126. lfx/components/ollama/ollama.py +24 -5
  127. lfx/components/processing/__init__.py +9 -60
  128. lfx/components/processing/converter.py +1 -1
  129. lfx/components/processing/dataframe_operations.py +1 -1
  130. lfx/components/processing/parse_json_data.py +2 -2
  131. lfx/components/processing/parser.py +1 -1
  132. lfx/components/processing/split_text.py +1 -1
  133. lfx/components/qdrant/qdrant.py +1 -1
  134. lfx/components/redis/redis.py +1 -1
  135. lfx/components/twelvelabs/split_video.py +10 -0
  136. lfx/components/twelvelabs/video_file.py +12 -0
  137. lfx/components/utilities/__init__.py +43 -0
  138. lfx/components/{helpers → utilities}/calculator_core.py +1 -1
  139. lfx/components/{helpers → utilities}/current_date.py +1 -1
  140. lfx/components/{processing → utilities}/python_repl_core.py +1 -1
  141. lfx/components/vectorstores/local_db.py +9 -0
  142. lfx/components/youtube/youtube_transcripts.py +118 -30
  143. lfx/custom/custom_component/component.py +57 -1
  144. lfx/custom/custom_component/custom_component.py +68 -6
  145. lfx/custom/directory_reader/directory_reader.py +5 -2
  146. lfx/graph/edge/base.py +43 -20
  147. lfx/graph/state/model.py +15 -2
  148. lfx/graph/utils.py +6 -0
  149. lfx/graph/vertex/param_handler.py +10 -7
  150. lfx/helpers/__init__.py +12 -0
  151. lfx/helpers/flow.py +117 -0
  152. lfx/inputs/input_mixin.py +24 -1
  153. lfx/inputs/inputs.py +13 -1
  154. lfx/interface/components.py +161 -83
  155. lfx/log/logger.py +5 -3
  156. lfx/schema/image.py +2 -12
  157. lfx/services/database/__init__.py +5 -0
  158. lfx/services/database/service.py +25 -0
  159. lfx/services/deps.py +87 -22
  160. lfx/services/interfaces.py +5 -0
  161. lfx/services/manager.py +24 -10
  162. lfx/services/mcp_composer/service.py +1029 -162
  163. lfx/services/session.py +5 -0
  164. lfx/services/settings/auth.py +18 -11
  165. lfx/services/settings/base.py +56 -30
  166. lfx/services/settings/constants.py +8 -0
  167. lfx/services/storage/local.py +108 -46
  168. lfx/services/storage/service.py +171 -29
  169. lfx/template/field/base.py +3 -0
  170. lfx/utils/image.py +29 -11
  171. lfx/utils/ssrf_protection.py +384 -0
  172. lfx/utils/validate_cloud.py +26 -0
  173. {lfx_nightly-0.2.0.dev0.dist-info → lfx_nightly-0.2.0.dev41.dist-info}/METADATA +38 -22
  174. {lfx_nightly-0.2.0.dev0.dist-info → lfx_nightly-0.2.0.dev41.dist-info}/RECORD +189 -160
  175. {lfx_nightly-0.2.0.dev0.dist-info → lfx_nightly-0.2.0.dev41.dist-info}/WHEEL +1 -1
  176. lfx/components/agents/altk_agent.py +0 -366
  177. lfx/components/agents/cuga_agent.py +0 -1013
  178. lfx/components/docling/docling_remote_vlm.py +0 -284
  179. lfx/components/logic/run_flow.py +0 -71
  180. lfx/components/models/embedding_model.py +0 -195
  181. lfx/components/models/language_model.py +0 -144
  182. lfx/components/processing/dataframe_to_toolset.py +0 -259
  183. /lfx/components/{data → data_source}/mock_data.py +0 -0
  184. /lfx/components/{knowledge_bases → files_and_knowledge}/ingestion.py +0 -0
  185. /lfx/components/{logic → flow_controls}/data_conditional_router.py +0 -0
  186. /lfx/components/{logic → flow_controls}/flow_tool.py +0 -0
  187. /lfx/components/{logic → flow_controls}/listen.py +0 -0
  188. /lfx/components/{logic → flow_controls}/notify.py +0 -0
  189. /lfx/components/{logic → flow_controls}/pass_message.py +0 -0
  190. /lfx/components/{logic → flow_controls}/sub_flow.py +0 -0
  191. /lfx/components/{processing → models_and_agents}/prompt.py +0 -0
  192. /lfx/components/{helpers → processing}/create_list.py +0 -0
  193. /lfx/components/{helpers → processing}/output_parser.py +0 -0
  194. /lfx/components/{helpers → processing}/store_message.py +0 -0
  195. /lfx/components/{helpers → utilities}/id_generator.py +0 -0
  196. {lfx_nightly-0.2.0.dev0.dist-info → lfx_nightly-0.2.0.dev41.dist-info}/entry_points.txt +0 -0
@@ -1,6 +1,9 @@
1
- from langchain_experimental.agents.agent_toolkits.csv.base import create_csv_agent
1
+ import contextlib
2
+ import tempfile
3
+ from pathlib import Path
2
4
 
3
5
  from lfx.base.agents.agent import LCAgentComponent
6
+ from lfx.base.data.storage_utils import read_file_bytes
4
7
  from lfx.field_typing import AgentExecutor
5
8
  from lfx.inputs.inputs import (
6
9
  DictInput,
@@ -10,7 +13,9 @@ from lfx.inputs.inputs import (
10
13
  MessageTextInput,
11
14
  )
12
15
  from lfx.schema.message import Message
16
+ from lfx.services.deps import get_settings_service
13
17
  from lfx.template.field.base import Output
18
+ from lfx.utils.async_helpers import run_until_complete
14
19
 
15
20
 
16
21
  class CSVAgentComponent(LCAgentComponent):
@@ -70,32 +75,60 @@ class CSVAgentComponent(LCAgentComponent):
70
75
  return self.path
71
76
 
72
77
  def build_agent_response(self) -> Message:
73
- agent_kwargs = {
74
- "verbose": self.verbose,
75
- "allow_dangerous_code": True,
76
- }
78
+ """Build and execute the CSV agent, returning the response."""
79
+ try:
80
+ from langchain_experimental.agents.agent_toolkits.csv.base import create_csv_agent
81
+ except ImportError as e:
82
+ msg = (
83
+ "langchain-experimental is not installed. Please install it with `pip install langchain-experimental`."
84
+ )
85
+ raise ImportError(msg) from e
77
86
 
78
- agent_csv = create_csv_agent(
79
- llm=self.llm,
80
- path=self._path(),
81
- agent_type=self.agent_type,
82
- handle_parsing_errors=self.handle_parsing_errors,
83
- pandas_kwargs=self.pandas_kwargs,
84
- **agent_kwargs,
85
- )
87
+ try:
88
+ agent_kwargs = {
89
+ "verbose": self.verbose,
90
+ "allow_dangerous_code": True,
91
+ }
92
+
93
+ # Get local path (downloads from S3 if needed)
94
+ local_path = self._get_local_path()
86
95
 
87
- result = agent_csv.invoke({"input": self.input_value})
88
- return Message(text=str(result["output"]))
96
+ agent_csv = create_csv_agent(
97
+ llm=self.llm,
98
+ path=local_path,
99
+ agent_type=self.agent_type,
100
+ handle_parsing_errors=self.handle_parsing_errors,
101
+ pandas_kwargs=self.pandas_kwargs,
102
+ **agent_kwargs,
103
+ )
104
+
105
+ result = agent_csv.invoke({"input": self.input_value})
106
+ return Message(text=str(result["output"]))
107
+
108
+ finally:
109
+ # Clean up temp file if created
110
+ self._cleanup_temp_file()
89
111
 
90
112
  def build_agent(self) -> AgentExecutor:
113
+ try:
114
+ from langchain_experimental.agents.agent_toolkits.csv.base import create_csv_agent
115
+ except ImportError as e:
116
+ msg = (
117
+ "langchain-experimental is not installed. Please install it with `pip install langchain-experimental`."
118
+ )
119
+ raise ImportError(msg) from e
120
+
91
121
  agent_kwargs = {
92
122
  "verbose": self.verbose,
93
123
  "allow_dangerous_code": True,
94
124
  }
95
125
 
126
+ # Get local path (downloads from S3 if needed)
127
+ local_path = self._get_local_path()
128
+
96
129
  agent_csv = create_csv_agent(
97
130
  llm=self.llm,
98
- path=self._path(),
131
+ path=local_path,
99
132
  agent_type=self.agent_type,
100
133
  handle_parsing_errors=self.handle_parsing_errors,
101
134
  pandas_kwargs=self.pandas_kwargs,
@@ -104,4 +137,39 @@ class CSVAgentComponent(LCAgentComponent):
104
137
 
105
138
  self.status = Message(text=str(agent_csv))
106
139
 
140
+ # Note: Temp file will be cleaned up when the component is destroyed or
141
+ # when build_agent_response is called
107
142
  return agent_csv
143
+
144
+ def _get_local_path(self) -> str:
145
+ """Get a local file path, downloading from S3 storage if necessary.
146
+
147
+ Returns:
148
+ str: Local file path that can be used by LangChain
149
+ """
150
+ file_path = self._path()
151
+ settings = get_settings_service().settings
152
+
153
+ # If using S3 storage, download the file to temp
154
+ if settings.storage_type == "s3":
155
+ # Download from S3 to temp file
156
+ csv_bytes = run_until_complete(read_file_bytes(file_path))
157
+
158
+ # Create temp file with .csv extension
159
+ suffix = Path(file_path.split("/")[-1]).suffix or ".csv"
160
+ with tempfile.NamedTemporaryFile(mode="wb", suffix=suffix, delete=False) as tmp_file:
161
+ tmp_file.write(csv_bytes)
162
+ temp_path = tmp_file.name
163
+
164
+ # Store temp path for cleanup
165
+ self._temp_file_path = temp_path
166
+ return temp_path
167
+
168
+ # Local storage - return path as-is
169
+ return file_path
170
+
171
+ def _cleanup_temp_file(self) -> None:
172
+ """Clean up temporary file if one was created."""
173
+ if hasattr(self, "_temp_file_path"):
174
+ with contextlib.suppress(Exception):
175
+ Path(self._temp_file_path).unlink() # Ignore cleanup errors
@@ -1,13 +1,15 @@
1
+ import contextlib
2
+ import tempfile
1
3
  from pathlib import Path
2
4
 
3
5
  import yaml
4
6
  from langchain.agents import AgentExecutor
5
- from langchain_community.agent_toolkits import create_json_agent
6
- from langchain_community.agent_toolkits.json.toolkit import JsonToolkit
7
- from langchain_community.tools.json.tool import JsonSpec
8
7
 
9
8
  from lfx.base.agents.agent import LCAgentComponent
9
+ from lfx.base.data.storage_utils import read_file_bytes
10
10
  from lfx.inputs.inputs import FileInput, HandleInput
11
+ from lfx.services.deps import get_settings_service
12
+ from lfx.utils.async_helpers import run_until_complete
11
13
 
12
14
 
13
15
  class JsonAgentComponent(LCAgentComponent):
@@ -32,14 +34,67 @@ class JsonAgentComponent(LCAgentComponent):
32
34
  ),
33
35
  ]
34
36
 
37
+ def _get_local_path(self) -> Path:
38
+ """Get a local file path, downloading from S3 storage if necessary.
39
+
40
+ Returns:
41
+ Path: Local file path that can be used by LangChain
42
+ """
43
+ file_path = self.path
44
+ settings = get_settings_service().settings
45
+
46
+ # If using S3 storage, download the file to temp
47
+ if settings.storage_type == "s3":
48
+ # Download from S3 to temp file
49
+ file_bytes = run_until_complete(read_file_bytes(file_path))
50
+
51
+ # Create temp file with appropriate extension
52
+ suffix = Path(file_path.split("/")[-1]).suffix or ".json"
53
+ with tempfile.NamedTemporaryFile(mode="wb", suffix=suffix, delete=False) as tmp_file:
54
+ tmp_file.write(file_bytes)
55
+ temp_path = tmp_file.name
56
+
57
+ # Store temp path for cleanup
58
+ self._temp_file_path = temp_path
59
+ return Path(temp_path)
60
+
61
+ # Local storage - return as Path
62
+ return Path(file_path)
63
+
64
+ def _cleanup_temp_file(self) -> None:
65
+ """Clean up temporary file if one was created."""
66
+ if hasattr(self, "_temp_file_path"):
67
+ with contextlib.suppress(Exception):
68
+ Path(self._temp_file_path).unlink() # Ignore cleanup errors
69
+
35
70
  def build_agent(self) -> AgentExecutor:
36
- path = Path(self.path)
37
- if path.suffix in {"yaml", "yml"}:
38
- with path.open(encoding="utf-8") as file:
39
- yaml_dict = yaml.safe_load(file)
40
- spec = JsonSpec(dict_=yaml_dict)
41
- else:
42
- spec = JsonSpec.from_file(path)
43
- toolkit = JsonToolkit(spec=spec)
71
+ """Build the JSON agent executor."""
72
+ try:
73
+ from langchain_community.agent_toolkits import create_json_agent
74
+ from langchain_community.agent_toolkits.json.toolkit import JsonToolkit
75
+ from langchain_community.tools.json.tool import JsonSpec
76
+ except ImportError as e:
77
+ msg = "langchain-community is not installed. Please install it with `pip install langchain-community`."
78
+ raise ImportError(msg) from e
79
+
80
+ try:
81
+ # Get local path (downloads from S3 if needed)
82
+ path = self._get_local_path()
44
83
 
45
- return create_json_agent(llm=self.llm, toolkit=toolkit, **self.get_agent_kwargs())
84
+ if path.suffix in {".yaml", ".yml"}:
85
+ with path.open(encoding="utf-8") as file:
86
+ yaml_dict = yaml.safe_load(file)
87
+ spec = JsonSpec(dict_=yaml_dict)
88
+ else:
89
+ spec = JsonSpec.from_file(str(path))
90
+ toolkit = JsonToolkit(spec=spec)
91
+
92
+ agent = create_json_agent(llm=self.llm, toolkit=toolkit, **self.get_agent_kwargs())
93
+ except Exception:
94
+ # Make sure to clean up temp file on error
95
+ self._cleanup_temp_file()
96
+ raise
97
+ else:
98
+ # Clean up temp file after agent is created
99
+ self._cleanup_temp_file()
100
+ return agent
@@ -9,7 +9,7 @@ from lfx.inputs.inputs import DataInput, DropdownInput, IntInput
9
9
  class LanguageRecursiveTextSplitterComponent(LCTextSplitterComponent):
10
10
  display_name: str = "Language Recursive Text Splitter"
11
11
  description: str = "Split text into chunks of a specified length based on language."
12
- documentation: str = "https://docs.langflow.org/components/text-splitters#languagerecursivetextsplitter"
12
+ documentation: str = "https://docs.langflow.org/bundles-langchain"
13
13
  name = "LanguageRecursiveTextSplitter"
14
14
  icon = "LangChain"
15
15
 
@@ -0,0 +1,46 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from lfx.components._importing import import_mod
6
+
7
+ if TYPE_CHECKING:
8
+ from lfx.components.llm_operations.batch_run import BatchRunComponent
9
+ from lfx.components.llm_operations.lambda_filter import SmartTransformComponent
10
+ from lfx.components.llm_operations.llm_conditional_router import SmartRouterComponent
11
+ from lfx.components.llm_operations.llm_selector import LLMSelectorComponent
12
+ from lfx.components.llm_operations.structured_output import StructuredOutputComponent
13
+
14
+ _dynamic_imports = {
15
+ "BatchRunComponent": "batch_run",
16
+ "SmartTransformComponent": "lambda_filter",
17
+ "SmartRouterComponent": "llm_conditional_router",
18
+ "LLMSelectorComponent": "llm_selector",
19
+ "StructuredOutputComponent": "structured_output",
20
+ }
21
+
22
+ __all__ = [
23
+ "BatchRunComponent",
24
+ "LLMSelectorComponent",
25
+ "SmartRouterComponent",
26
+ "SmartTransformComponent",
27
+ "StructuredOutputComponent",
28
+ ]
29
+
30
+
31
+ def __getattr__(attr_name: str) -> Any:
32
+ """Lazily import LLM operation components on attribute access."""
33
+ if attr_name not in _dynamic_imports:
34
+ msg = f"module '{__name__}' has no attribute '{attr_name}'"
35
+ raise AttributeError(msg)
36
+ try:
37
+ result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
38
+ except (ModuleNotFoundError, ImportError, AttributeError) as e:
39
+ msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
40
+ raise AttributeError(msg) from e
41
+ globals()[attr_name] = result
42
+ return result
43
+
44
+
45
+ def __dir__() -> list[str]:
46
+ return list(__all__)
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
16
16
  class BatchRunComponent(Component):
17
17
  display_name = "Batch Run"
18
18
  description = "Runs an LLM on each row of a DataFrame column. If no column is specified, all columns are used."
19
- documentation: str = "https://docs.langflow.org/components-processing#batch-run"
19
+ documentation: str = "https://docs.langflow.org/batch-run"
20
20
  icon = "List"
21
21
 
22
22
  inputs = [
@@ -159,13 +159,22 @@ class BatchRunComponent(Component):
159
159
  ]
160
160
 
161
161
  # Configure the model with project info and callbacks
162
- model = model.with_config(
163
- {
164
- "run_name": self.display_name,
165
- "project_name": self.get_project_name(),
166
- "callbacks": self.get_langchain_callbacks(),
167
- }
168
- )
162
+ # Some models (e.g., ChatWatsonx) may have serialization issues with with_config()
163
+ # due to SecretStr or other non-serializable attributes
164
+ try:
165
+ model = model.with_config(
166
+ {
167
+ "run_name": self.display_name,
168
+ "project_name": self.get_project_name(),
169
+ "callbacks": self.get_langchain_callbacks(),
170
+ }
171
+ )
172
+ except (TypeError, ValueError, AttributeError) as e:
173
+ # Log warning and continue without configuration
174
+ await logger.awarning(
175
+ f"Could not configure model with callbacks and project info: {e!s}. "
176
+ "Proceeding with batch processing without configuration."
177
+ )
169
178
  # Process batches and track progress
170
179
  responses_with_idx = list(
171
180
  zip(
@@ -16,7 +16,7 @@ if TYPE_CHECKING:
16
16
  class LambdaFilterComponent(Component):
17
17
  display_name = "Smart Transform"
18
18
  description = "Uses an LLM to generate a function for filtering or transforming structured data."
19
- documentation: str = "https://docs.langflow.org/components-processing#smart-transform"
19
+ documentation: str = "https://docs.langflow.org/smart-transform"
20
20
  icon = "square-function"
21
21
  name = "Smart Transform"
22
22
 
@@ -9,7 +9,7 @@ from lfx.schema.table import EditMode
9
9
  class SmartRouterComponent(Component):
10
10
  display_name = "Smart Router"
11
11
  description = "Routes an input message using LLM-based categorization."
12
- icon = "equal"
12
+ icon = "route"
13
13
  name = "SmartRouter"
14
14
 
15
15
  def __init__(self, **kwargs):
@@ -14,10 +14,10 @@ from lfx.schema.message import Message
14
14
  from lfx.template.field.base import Output
15
15
 
16
16
 
17
- class LLMRouterComponent(Component):
18
- display_name = "LLM Router"
17
+ class LLMSelectorComponent(Component):
18
+ display_name = "LLM Selector"
19
19
  description = "Routes the input to the most appropriate LLM based on OpenRouter model specifications"
20
- documentation: str = "https://docs.langflow.org/components-processing#llm-router"
20
+ documentation: str = "https://docs.langflow.org/llm-selector"
21
21
  icon = "git-branch"
22
22
 
23
23
  # Constants for magic values
@@ -20,7 +20,7 @@ from lfx.schema.table import EditMode
20
20
  class StructuredOutputComponent(Component):
21
21
  display_name = "Structured Output"
22
22
  description = "Uses an LLM to generate structured data. Ideal for extraction and consistency."
23
- documentation: str = "https://docs.langflow.org/components-processing#structured-output"
23
+ documentation: str = "https://docs.langflow.org/structured-output"
24
24
  name = "StructuredOutput"
25
25
  icon = "braces"
26
26
 
@@ -1,5 +1,12 @@
1
+ """Logic module - backwards compatibility alias for flow_controls.
2
+
3
+ This module provides backwards compatibility by forwarding imports
4
+ to flow_controls where the actual logic components are located.
5
+ """
6
+
1
7
  from __future__ import annotations
2
8
 
9
+ import sys
3
10
  from typing import TYPE_CHECKING, Any
4
11
 
5
12
  from lfx.components._importing import import_mod
@@ -36,12 +43,131 @@ __all__ = [
36
43
  "SubFlowComponent",
37
44
  ]
38
45
 
46
+ # Register redirected submodules in sys.modules for direct importlib.import_module() calls
47
+ # This allows imports like: import lfx.components.logic.listen
48
+ _redirected_submodules = {
49
+ "lfx.components.logic.listen": "lfx.components.flow_controls.listen",
50
+ "lfx.components.logic.loop": "lfx.components.flow_controls.loop",
51
+ "lfx.components.logic.notify": "lfx.components.flow_controls.notify",
52
+ "lfx.components.logic.pass_message": "lfx.components.flow_controls.pass_message",
53
+ "lfx.components.logic.conditional_router": "lfx.components.flow_controls.conditional_router",
54
+ "lfx.components.logic.data_conditional_router": "lfx.components.flow_controls.data_conditional_router",
55
+ "lfx.components.logic.flow_tool": "lfx.components.flow_controls.flow_tool",
56
+ "lfx.components.logic.run_flow": "lfx.components.flow_controls.run_flow",
57
+ "lfx.components.logic.sub_flow": "lfx.components.flow_controls.sub_flow",
58
+ }
59
+
60
+ for old_path, new_path in _redirected_submodules.items():
61
+ if old_path not in sys.modules:
62
+ # Use a lazy loader that imports the actual module when accessed
63
+ class _RedirectedModule:
64
+ def __init__(self, target_path: str, original_path: str):
65
+ self._target_path = target_path
66
+ self._original_path = original_path
67
+ self._module = None
68
+
69
+ def __getattr__(self, name: str) -> Any:
70
+ if self._module is None:
71
+ from importlib import import_module
72
+
73
+ self._module = import_module(self._target_path)
74
+ # Also register under the original path for future imports
75
+ sys.modules[self._original_path] = self._module
76
+ return getattr(self._module, name)
77
+
78
+ def __repr__(self) -> str:
79
+ return f"<redirected module '{self._original_path}' -> '{self._target_path}'>"
80
+
81
+ sys.modules[old_path] = _RedirectedModule(new_path, old_path)
82
+
39
83
 
40
84
  def __getattr__(attr_name: str) -> Any:
41
85
  """Lazily import logic components on attribute access."""
86
+ # Handle submodule access for backwards compatibility
87
+ if attr_name == "listen":
88
+ from importlib import import_module
89
+
90
+ result = import_module("lfx.components.flow_controls.listen")
91
+ globals()[attr_name] = result
92
+ return result
93
+ if attr_name == "loop":
94
+ from importlib import import_module
95
+
96
+ result = import_module("lfx.components.flow_controls.loop")
97
+ globals()[attr_name] = result
98
+ return result
99
+ if attr_name == "notify":
100
+ from importlib import import_module
101
+
102
+ result = import_module("lfx.components.flow_controls.notify")
103
+ globals()[attr_name] = result
104
+ return result
105
+ if attr_name == "pass_message":
106
+ from importlib import import_module
107
+
108
+ result = import_module("lfx.components.flow_controls.pass_message")
109
+ globals()[attr_name] = result
110
+ return result
111
+ if attr_name == "conditional_router":
112
+ from importlib import import_module
113
+
114
+ result = import_module("lfx.components.flow_controls.conditional_router")
115
+ globals()[attr_name] = result
116
+ return result
117
+ if attr_name == "data_conditional_router":
118
+ from importlib import import_module
119
+
120
+ result = import_module("lfx.components.flow_controls.data_conditional_router")
121
+ globals()[attr_name] = result
122
+ return result
123
+ if attr_name == "flow_tool":
124
+ from importlib import import_module
125
+
126
+ result = import_module("lfx.components.flow_controls.flow_tool")
127
+ globals()[attr_name] = result
128
+ return result
129
+ if attr_name == "run_flow":
130
+ from importlib import import_module
131
+
132
+ result = import_module("lfx.components.flow_controls.run_flow")
133
+ globals()[attr_name] = result
134
+ return result
135
+ if attr_name == "sub_flow":
136
+ from importlib import import_module
137
+
138
+ result = import_module("lfx.components.flow_controls.sub_flow")
139
+ globals()[attr_name] = result
140
+ return result
141
+
42
142
  if attr_name not in _dynamic_imports:
43
143
  msg = f"module '{__name__}' has no attribute '{attr_name}'"
44
144
  raise AttributeError(msg)
145
+
146
+ # Most logic components were moved to flow_controls
147
+ # Forward them to flow_controls for backwards compatibility
148
+ if attr_name in (
149
+ "ConditionalRouterComponent",
150
+ "DataConditionalRouterComponent",
151
+ "FlowToolComponent",
152
+ "LoopComponent",
153
+ "PassMessageComponent",
154
+ "RunFlowComponent",
155
+ "SubFlowComponent",
156
+ ):
157
+ from lfx.components import flow_controls
158
+
159
+ result = getattr(flow_controls, attr_name)
160
+ globals()[attr_name] = result
161
+ return result
162
+
163
+ # SmartRouterComponent was moved to llm_operations
164
+ if attr_name == "SmartRouterComponent":
165
+ from lfx.components import llm_operations
166
+
167
+ result = getattr(llm_operations, attr_name)
168
+ globals()[attr_name] = result
169
+ return result
170
+
45
171
  try:
46
172
  result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
47
173
  except (ModuleNotFoundError, ImportError, AttributeError) as e:
@@ -7,6 +7,11 @@ from lfx.inputs.inputs import DictInput, HandleInput, MessageTextInput, NestedDi
7
7
  from lfx.io import Output
8
8
  from lfx.log.logger import logger
9
9
  from lfx.schema.data import Data
10
+ from lfx.utils.validate_cloud import raise_error_if_astra_cloud_disable_component
11
+
12
+ disable_component_in_astra_cloud_msg = (
13
+ "Mem0 chat memory is not supported in Astra cloud environment. Please use local storage mode or mem0 cloud."
14
+ )
10
15
 
11
16
 
12
17
  class Mem0MemoryComponent(LCChatMemoryComponent):
@@ -80,6 +85,8 @@ class Mem0MemoryComponent(LCChatMemoryComponent):
80
85
 
81
86
  def build_mem0(self) -> Memory:
82
87
  """Initializes a Mem0 memory instance based on provided configuration and API keys."""
88
+ # Check if we're in Astra cloud environment and raise an error if we are.
89
+ raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)
83
90
  if self.openai_api_key:
84
91
  os.environ["OPENAI_API_KEY"] = self.openai_api_key
85
92
 
@@ -95,6 +102,8 @@ class Mem0MemoryComponent(LCChatMemoryComponent):
95
102
 
96
103
  def ingest_data(self) -> Memory:
97
104
  """Ingests a new message into Mem0 memory and returns the updated memory instance."""
105
+ # Check if we're in Astra cloud environment and raise an error if we are.
106
+ raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)
98
107
  mem0_memory = self.existing_memory or self.build_mem0()
99
108
 
100
109
  if not self.ingest_message or not self.user_id:
@@ -115,6 +124,8 @@ class Mem0MemoryComponent(LCChatMemoryComponent):
115
124
 
116
125
  def build_search_results(self) -> Data:
117
126
  """Searches the Mem0 memory for related messages based on the search query and returns the results."""
127
+ # Check if we're in Astra cloud environment and raise an error if we are.
128
+ raise_error_if_astra_cloud_disable_component(disable_component_in_astra_cloud_msg)
118
129
  mem0_memory = self.ingest_data()
119
130
  search_query = self.search_query
120
131
  user_id = self.user_id
@@ -1,28 +1,82 @@
1
+ """Models module - backwards compatibility alias for models_and_agents.
2
+
3
+ This module provides backwards compatibility by forwarding model-related imports
4
+ to models_and_agents where the actual model components are located.
5
+ """
6
+
1
7
  from __future__ import annotations
2
8
 
3
- from typing import TYPE_CHECKING, Any
9
+ import sys
10
+ from typing import Any
4
11
 
5
12
  from lfx.components._importing import import_mod
6
13
 
7
- if TYPE_CHECKING:
8
- from lfx.components.models.embedding_model import EmbeddingModelComponent
9
- from lfx.components.models.language_model import LanguageModelComponent
10
-
14
+ # Forward model components from models_and_agents
11
15
  _dynamic_imports = {
12
- "EmbeddingModelComponent": "embedding_model",
13
16
  "LanguageModelComponent": "language_model",
17
+ "EmbeddingModelComponent": "embedding_model",
18
+ }
19
+
20
+ __all__ = [
21
+ "EmbeddingModelComponent",
22
+ "LanguageModelComponent",
23
+ ]
24
+
25
+ # Register redirected submodules in sys.modules for direct importlib.import_module() calls
26
+ # This allows imports like: import lfx.components.models.embedding_model
27
+ _redirected_submodules = {
28
+ "lfx.components.models.embedding_model": "lfx.components.models_and_agents.embedding_model",
29
+ "lfx.components.models.language_model": "lfx.components.models_and_agents.language_model",
14
30
  }
15
31
 
16
- __all__ = ["EmbeddingModelComponent", "LanguageModelComponent"]
32
+ for old_path, new_path in _redirected_submodules.items():
33
+ if old_path not in sys.modules:
34
+ # Use a lazy loader that imports the actual module when accessed
35
+ class _RedirectedModule:
36
+ def __init__(self, target_path: str, original_path: str):
37
+ self._target_path = target_path
38
+ self._original_path = original_path
39
+ self._module = None
40
+
41
+ def __getattr__(self, name: str) -> Any:
42
+ if self._module is None:
43
+ from importlib import import_module
44
+
45
+ self._module = import_module(self._target_path)
46
+ # Also register under the original path for future imports
47
+ sys.modules[self._original_path] = self._module
48
+ return getattr(self._module, name)
49
+
50
+ def __repr__(self) -> str:
51
+ return f"<redirected module '{self._original_path}' -> '{self._target_path}'>"
52
+
53
+ sys.modules[old_path] = _RedirectedModule(new_path, old_path)
17
54
 
18
55
 
19
56
  def __getattr__(attr_name: str) -> Any:
20
- """Lazily import model components on attribute access."""
57
+ """Forward attribute access to models_and_agents components."""
58
+ # Handle submodule access for backwards compatibility
59
+ if attr_name == "embedding_model":
60
+ from importlib import import_module
61
+
62
+ result = import_module("lfx.components.models_and_agents.embedding_model")
63
+ globals()[attr_name] = result
64
+ return result
65
+ if attr_name == "language_model":
66
+ from importlib import import_module
67
+
68
+ result = import_module("lfx.components.models_and_agents.language_model")
69
+ globals()[attr_name] = result
70
+ return result
71
+
21
72
  if attr_name not in _dynamic_imports:
22
73
  msg = f"module '{__name__}' has no attribute '{attr_name}'"
23
74
  raise AttributeError(msg)
75
+
76
+ # Import from models_and_agents using the correct package path
77
+ package = "lfx.components.models_and_agents"
24
78
  try:
25
- result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
79
+ result = import_mod(attr_name, _dynamic_imports[attr_name], package)
26
80
  except (ModuleNotFoundError, ImportError, AttributeError) as e:
27
81
  msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
28
82
  raise AttributeError(msg) from e
@@ -31,4 +85,5 @@ def __getattr__(attr_name: str) -> Any:
31
85
 
32
86
 
33
87
  def __dir__() -> list[str]:
88
+ """Return directory of available components."""
34
89
  return list(__all__)