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.
- lfx/_assets/component_index.json +1 -1
- lfx/base/agents/agent.py +21 -4
- lfx/base/agents/altk_base_agent.py +393 -0
- lfx/base/agents/altk_tool_wrappers.py +565 -0
- lfx/base/agents/events.py +2 -1
- lfx/base/composio/composio_base.py +159 -224
- lfx/base/data/base_file.py +97 -20
- lfx/base/data/docling_utils.py +61 -10
- lfx/base/data/storage_utils.py +301 -0
- lfx/base/data/utils.py +178 -14
- lfx/base/mcp/util.py +2 -2
- lfx/base/models/anthropic_constants.py +21 -12
- lfx/base/models/groq_constants.py +74 -58
- lfx/base/models/groq_model_discovery.py +265 -0
- lfx/base/models/model.py +1 -1
- lfx/base/models/model_utils.py +100 -0
- lfx/base/models/openai_constants.py +7 -0
- lfx/base/models/watsonx_constants.py +32 -8
- lfx/base/tools/run_flow.py +601 -129
- lfx/cli/commands.py +9 -4
- lfx/cli/common.py +2 -2
- lfx/cli/run.py +1 -1
- lfx/cli/script_loader.py +53 -11
- lfx/components/Notion/create_page.py +1 -1
- lfx/components/Notion/list_database_properties.py +1 -1
- lfx/components/Notion/list_pages.py +1 -1
- lfx/components/Notion/list_users.py +1 -1
- lfx/components/Notion/page_content_viewer.py +1 -1
- lfx/components/Notion/search.py +1 -1
- lfx/components/Notion/update_page_property.py +1 -1
- lfx/components/__init__.py +19 -5
- lfx/components/{agents → altk}/__init__.py +5 -9
- lfx/components/altk/altk_agent.py +193 -0
- lfx/components/apify/apify_actor.py +1 -1
- lfx/components/composio/__init__.py +70 -18
- lfx/components/composio/apollo_composio.py +11 -0
- lfx/components/composio/bitbucket_composio.py +11 -0
- lfx/components/composio/canva_composio.py +11 -0
- lfx/components/composio/coda_composio.py +11 -0
- lfx/components/composio/composio_api.py +10 -0
- lfx/components/composio/discord_composio.py +1 -1
- lfx/components/composio/elevenlabs_composio.py +11 -0
- lfx/components/composio/exa_composio.py +11 -0
- lfx/components/composio/firecrawl_composio.py +11 -0
- lfx/components/composio/fireflies_composio.py +11 -0
- lfx/components/composio/gmail_composio.py +1 -1
- lfx/components/composio/googlebigquery_composio.py +11 -0
- lfx/components/composio/googlecalendar_composio.py +1 -1
- lfx/components/composio/googledocs_composio.py +1 -1
- lfx/components/composio/googlemeet_composio.py +1 -1
- lfx/components/composio/googlesheets_composio.py +1 -1
- lfx/components/composio/googletasks_composio.py +1 -1
- lfx/components/composio/heygen_composio.py +11 -0
- lfx/components/composio/mem0_composio.py +11 -0
- lfx/components/composio/peopledatalabs_composio.py +11 -0
- lfx/components/composio/perplexityai_composio.py +11 -0
- lfx/components/composio/serpapi_composio.py +11 -0
- lfx/components/composio/slack_composio.py +3 -574
- lfx/components/composio/slackbot_composio.py +1 -1
- lfx/components/composio/snowflake_composio.py +11 -0
- lfx/components/composio/tavily_composio.py +11 -0
- lfx/components/composio/youtube_composio.py +2 -2
- lfx/components/cuga/__init__.py +34 -0
- lfx/components/cuga/cuga_agent.py +730 -0
- lfx/components/data/__init__.py +78 -28
- lfx/components/data_source/__init__.py +58 -0
- lfx/components/{data → data_source}/api_request.py +26 -3
- lfx/components/{data → data_source}/csv_to_data.py +15 -10
- lfx/components/{data → data_source}/json_to_data.py +15 -8
- lfx/components/{data → data_source}/news_search.py +1 -1
- lfx/components/{data → data_source}/rss.py +1 -1
- lfx/components/{data → data_source}/sql_executor.py +1 -1
- lfx/components/{data → data_source}/url.py +1 -1
- lfx/components/{data → data_source}/web_search.py +1 -1
- lfx/components/datastax/astradb_cql.py +1 -1
- lfx/components/datastax/astradb_graph.py +1 -1
- lfx/components/datastax/astradb_tool.py +1 -1
- lfx/components/datastax/astradb_vectorstore.py +1 -1
- lfx/components/datastax/hcd.py +1 -1
- lfx/components/deactivated/json_document_builder.py +1 -1
- lfx/components/docling/__init__.py +0 -3
- lfx/components/docling/chunk_docling_document.py +3 -1
- lfx/components/docling/export_docling_document.py +3 -1
- lfx/components/elastic/elasticsearch.py +1 -1
- lfx/components/files_and_knowledge/__init__.py +47 -0
- lfx/components/{data → files_and_knowledge}/directory.py +1 -1
- lfx/components/{data → files_and_knowledge}/file.py +304 -24
- lfx/components/{knowledge_bases → files_and_knowledge}/retrieval.py +2 -2
- lfx/components/{data → files_and_knowledge}/save_file.py +218 -31
- lfx/components/flow_controls/__init__.py +58 -0
- lfx/components/{logic → flow_controls}/conditional_router.py +1 -1
- lfx/components/{logic → flow_controls}/loop.py +43 -9
- lfx/components/flow_controls/run_flow.py +108 -0
- lfx/components/glean/glean_search_api.py +1 -1
- lfx/components/groq/groq.py +35 -28
- lfx/components/helpers/__init__.py +102 -0
- lfx/components/ibm/watsonx.py +7 -1
- lfx/components/input_output/__init__.py +3 -1
- lfx/components/input_output/chat.py +4 -3
- lfx/components/input_output/chat_output.py +10 -4
- lfx/components/input_output/text.py +1 -1
- lfx/components/input_output/text_output.py +1 -1
- lfx/components/{data → input_output}/webhook.py +1 -1
- lfx/components/knowledge_bases/__init__.py +59 -4
- lfx/components/langchain_utilities/character.py +1 -1
- lfx/components/langchain_utilities/csv_agent.py +84 -16
- lfx/components/langchain_utilities/json_agent.py +67 -12
- lfx/components/langchain_utilities/language_recursive.py +1 -1
- lfx/components/llm_operations/__init__.py +46 -0
- lfx/components/{processing → llm_operations}/batch_run.py +17 -8
- lfx/components/{processing → llm_operations}/lambda_filter.py +1 -1
- lfx/components/{logic → llm_operations}/llm_conditional_router.py +1 -1
- lfx/components/{processing/llm_router.py → llm_operations/llm_selector.py} +3 -3
- lfx/components/{processing → llm_operations}/structured_output.py +1 -1
- lfx/components/logic/__init__.py +126 -0
- lfx/components/mem0/mem0_chat_memory.py +11 -0
- lfx/components/models/__init__.py +64 -9
- lfx/components/models_and_agents/__init__.py +49 -0
- lfx/components/{agents → models_and_agents}/agent.py +6 -4
- lfx/components/models_and_agents/embedding_model.py +353 -0
- lfx/components/models_and_agents/language_model.py +398 -0
- lfx/components/{agents → models_and_agents}/mcp_component.py +53 -44
- lfx/components/{helpers → models_and_agents}/memory.py +1 -1
- lfx/components/nvidia/system_assist.py +1 -1
- lfx/components/olivya/olivya.py +1 -1
- lfx/components/ollama/ollama.py +24 -5
- lfx/components/processing/__init__.py +9 -60
- lfx/components/processing/converter.py +1 -1
- lfx/components/processing/dataframe_operations.py +1 -1
- lfx/components/processing/parse_json_data.py +2 -2
- lfx/components/processing/parser.py +1 -1
- lfx/components/processing/split_text.py +1 -1
- lfx/components/qdrant/qdrant.py +1 -1
- lfx/components/redis/redis.py +1 -1
- lfx/components/twelvelabs/split_video.py +10 -0
- lfx/components/twelvelabs/video_file.py +12 -0
- lfx/components/utilities/__init__.py +43 -0
- lfx/components/{helpers → utilities}/calculator_core.py +1 -1
- lfx/components/{helpers → utilities}/current_date.py +1 -1
- lfx/components/{processing → utilities}/python_repl_core.py +1 -1
- lfx/components/vectorstores/local_db.py +9 -0
- lfx/components/youtube/youtube_transcripts.py +118 -30
- lfx/custom/custom_component/component.py +57 -1
- lfx/custom/custom_component/custom_component.py +68 -6
- lfx/custom/directory_reader/directory_reader.py +5 -2
- lfx/graph/edge/base.py +43 -20
- lfx/graph/state/model.py +15 -2
- lfx/graph/utils.py +6 -0
- lfx/graph/vertex/param_handler.py +10 -7
- lfx/helpers/__init__.py +12 -0
- lfx/helpers/flow.py +117 -0
- lfx/inputs/input_mixin.py +24 -1
- lfx/inputs/inputs.py +13 -1
- lfx/interface/components.py +161 -83
- lfx/log/logger.py +5 -3
- lfx/schema/image.py +2 -12
- lfx/services/database/__init__.py +5 -0
- lfx/services/database/service.py +25 -0
- lfx/services/deps.py +87 -22
- lfx/services/interfaces.py +5 -0
- lfx/services/manager.py +24 -10
- lfx/services/mcp_composer/service.py +1029 -162
- lfx/services/session.py +5 -0
- lfx/services/settings/auth.py +18 -11
- lfx/services/settings/base.py +56 -30
- lfx/services/settings/constants.py +8 -0
- lfx/services/storage/local.py +108 -46
- lfx/services/storage/service.py +171 -29
- lfx/template/field/base.py +3 -0
- lfx/utils/image.py +29 -11
- lfx/utils/ssrf_protection.py +384 -0
- lfx/utils/validate_cloud.py +26 -0
- {lfx_nightly-0.2.0.dev0.dist-info → lfx_nightly-0.2.0.dev41.dist-info}/METADATA +38 -22
- {lfx_nightly-0.2.0.dev0.dist-info → lfx_nightly-0.2.0.dev41.dist-info}/RECORD +189 -160
- {lfx_nightly-0.2.0.dev0.dist-info → lfx_nightly-0.2.0.dev41.dist-info}/WHEEL +1 -1
- lfx/components/agents/altk_agent.py +0 -366
- lfx/components/agents/cuga_agent.py +0 -1013
- lfx/components/docling/docling_remote_vlm.py +0 -284
- lfx/components/logic/run_flow.py +0 -71
- lfx/components/models/embedding_model.py +0 -195
- lfx/components/models/language_model.py +0 -144
- lfx/components/processing/dataframe_to_toolset.py +0 -259
- /lfx/components/{data → data_source}/mock_data.py +0 -0
- /lfx/components/{knowledge_bases → files_and_knowledge}/ingestion.py +0 -0
- /lfx/components/{logic → flow_controls}/data_conditional_router.py +0 -0
- /lfx/components/{logic → flow_controls}/flow_tool.py +0 -0
- /lfx/components/{logic → flow_controls}/listen.py +0 -0
- /lfx/components/{logic → flow_controls}/notify.py +0 -0
- /lfx/components/{logic → flow_controls}/pass_message.py +0 -0
- /lfx/components/{logic → flow_controls}/sub_flow.py +0 -0
- /lfx/components/{processing → models_and_agents}/prompt.py +0 -0
- /lfx/components/{helpers → processing}/create_list.py +0 -0
- /lfx/components/{helpers → processing}/output_parser.py +0 -0
- /lfx/components/{helpers → processing}/store_message.py +0 -0
- /lfx/components/{helpers → utilities}/id_generator.py +0 -0
- {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
|
-
|
|
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
|
-
|
|
74
|
-
|
|
75
|
-
|
|
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
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
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
|
-
|
|
88
|
-
|
|
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=
|
|
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
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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
|
-
|
|
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/
|
|
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/
|
|
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
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
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/
|
|
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 = "
|
|
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
|
|
18
|
-
display_name = "LLM
|
|
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/
|
|
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/
|
|
23
|
+
documentation: str = "https://docs.langflow.org/structured-output"
|
|
24
24
|
name = "StructuredOutput"
|
|
25
25
|
icon = "braces"
|
|
26
26
|
|
lfx/components/logic/__init__.py
CHANGED
|
@@ -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
|
-
|
|
9
|
+
import sys
|
|
10
|
+
from typing import Any
|
|
4
11
|
|
|
5
12
|
from lfx.components._importing import import_mod
|
|
6
13
|
|
|
7
|
-
|
|
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
|
-
|
|
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
|
-
"""
|
|
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],
|
|
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__)
|