lfx-nightly 0.1.13.dev0__py3-none-any.whl → 0.2.0.dev0__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 +109 -29
- lfx/base/agents/events.py +102 -35
- lfx/base/agents/utils.py +15 -2
- lfx/base/composio/composio_base.py +24 -9
- lfx/base/datastax/__init__.py +5 -0
- lfx/{components/vectorstores/astradb.py → base/datastax/astradb_base.py} +84 -473
- lfx/base/io/chat.py +5 -4
- lfx/base/mcp/util.py +101 -15
- lfx/base/models/model_input_constants.py +74 -7
- lfx/base/models/ollama_constants.py +3 -0
- lfx/base/models/watsonx_constants.py +12 -0
- lfx/cli/commands.py +1 -1
- lfx/components/agents/__init__.py +3 -1
- lfx/components/agents/agent.py +47 -4
- lfx/components/agents/altk_agent.py +366 -0
- lfx/components/agents/cuga_agent.py +1 -1
- lfx/components/agents/mcp_component.py +32 -2
- lfx/components/amazon/amazon_bedrock_converse.py +1 -1
- lfx/components/apify/apify_actor.py +3 -3
- lfx/components/datastax/__init__.py +12 -6
- lfx/components/datastax/{astra_assistant_manager.py → astradb_assistant_manager.py} +1 -0
- lfx/components/datastax/astradb_chatmemory.py +40 -0
- lfx/components/datastax/astradb_cql.py +5 -31
- lfx/components/datastax/astradb_graph.py +9 -123
- lfx/components/datastax/astradb_tool.py +12 -52
- lfx/components/datastax/astradb_vectorstore.py +133 -976
- lfx/components/datastax/create_assistant.py +1 -0
- lfx/components/datastax/create_thread.py +1 -0
- lfx/components/datastax/dotenv.py +1 -0
- lfx/components/datastax/get_assistant.py +1 -0
- lfx/components/datastax/getenvvar.py +1 -0
- lfx/components/datastax/graph_rag.py +1 -1
- lfx/components/datastax/list_assistants.py +1 -0
- lfx/components/datastax/run.py +1 -0
- lfx/components/docling/__init__.py +3 -0
- lfx/components/docling/docling_remote_vlm.py +284 -0
- lfx/components/ibm/watsonx.py +25 -21
- lfx/components/input_output/chat.py +8 -0
- lfx/components/input_output/chat_output.py +8 -0
- lfx/components/knowledge_bases/ingestion.py +17 -9
- lfx/components/knowledge_bases/retrieval.py +16 -8
- lfx/components/logic/loop.py +4 -0
- lfx/components/mistral/mistral_embeddings.py +1 -1
- lfx/components/models/embedding_model.py +88 -7
- lfx/components/ollama/ollama.py +221 -14
- lfx/components/openrouter/openrouter.py +49 -147
- lfx/components/processing/parser.py +6 -1
- lfx/components/processing/structured_output.py +55 -17
- lfx/components/vectorstores/__init__.py +0 -6
- lfx/custom/custom_component/component.py +3 -2
- lfx/field_typing/constants.py +1 -0
- lfx/graph/edge/base.py +2 -2
- lfx/graph/graph/base.py +1 -1
- lfx/graph/graph/schema.py +3 -2
- lfx/graph/vertex/vertex_types.py +1 -1
- lfx/io/schema.py +6 -0
- lfx/schema/schema.py +5 -0
- {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev0.dist-info}/METADATA +1 -1
- {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev0.dist-info}/RECORD +63 -81
- lfx/components/datastax/astra_db.py +0 -77
- lfx/components/datastax/cassandra.py +0 -92
- lfx/components/vectorstores/astradb_graph.py +0 -326
- lfx/components/vectorstores/cassandra.py +0 -264
- lfx/components/vectorstores/cassandra_graph.py +0 -238
- lfx/components/vectorstores/chroma.py +0 -167
- lfx/components/vectorstores/clickhouse.py +0 -135
- lfx/components/vectorstores/couchbase.py +0 -102
- lfx/components/vectorstores/elasticsearch.py +0 -267
- lfx/components/vectorstores/faiss.py +0 -111
- lfx/components/vectorstores/graph_rag.py +0 -141
- lfx/components/vectorstores/hcd.py +0 -314
- lfx/components/vectorstores/milvus.py +0 -115
- lfx/components/vectorstores/mongodb_atlas.py +0 -213
- lfx/components/vectorstores/opensearch.py +0 -243
- lfx/components/vectorstores/pgvector.py +0 -72
- lfx/components/vectorstores/pinecone.py +0 -134
- lfx/components/vectorstores/qdrant.py +0 -109
- lfx/components/vectorstores/supabase.py +0 -76
- lfx/components/vectorstores/upstash.py +0 -124
- lfx/components/vectorstores/vectara.py +0 -97
- lfx/components/vectorstores/vectara_rag.py +0 -164
- lfx/components/vectorstores/weaviate.py +0 -89
- /lfx/components/datastax/{astra_vectorize.py → astradb_vectorize.py} +0 -0
- {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev0.dist-info}/WHEEL +0 -0
- {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev0.dist-info}/entry_points.txt +0 -0
lfx/base/io/chat.py
CHANGED
|
@@ -6,8 +6,9 @@ class ChatComponent(Component):
|
|
|
6
6
|
description = "Use as base for chat components."
|
|
7
7
|
|
|
8
8
|
def get_properties_from_source_component(self):
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
vertex = self.get_vertex()
|
|
10
|
+
if vertex and hasattr(vertex, "incoming_edges") and vertex.incoming_edges:
|
|
11
|
+
source_id = vertex.incoming_edges[0].source_id
|
|
11
12
|
source_vertex = self.graph.get_vertex(source_id)
|
|
12
13
|
component = source_vertex.custom_component
|
|
13
14
|
source = component.display_name
|
|
@@ -15,6 +16,6 @@ class ChatComponent(Component):
|
|
|
15
16
|
possible_attributes = ["model_name", "model_id", "model"]
|
|
16
17
|
for attribute in possible_attributes:
|
|
17
18
|
if hasattr(component, attribute) and getattr(component, attribute):
|
|
18
|
-
return getattr(component, attribute), icon, source, component.
|
|
19
|
-
return source, icon, component.display_name, component.
|
|
19
|
+
return getattr(component, attribute), icon, source, component.get_id()
|
|
20
|
+
return source, icon, component.display_name, component.get_id()
|
|
20
21
|
return None, None, None, None
|
lfx/base/mcp/util.py
CHANGED
|
@@ -35,13 +35,33 @@ HTTP_INTERNAL_SERVER_ERROR = 500
|
|
|
35
35
|
HTTP_UNAUTHORIZED = 401
|
|
36
36
|
HTTP_FORBIDDEN = 403
|
|
37
37
|
|
|
38
|
-
# MCP Session Manager constants
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
38
|
+
# MCP Session Manager constants - lazy loaded
|
|
39
|
+
_mcp_settings_cache: dict[str, Any] = {}
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _get_mcp_setting(key: str, default: Any = None) -> Any:
|
|
43
|
+
"""Lazy load MCP settings from settings service."""
|
|
44
|
+
if key not in _mcp_settings_cache:
|
|
45
|
+
settings = get_settings_service().settings
|
|
46
|
+
_mcp_settings_cache[key] = getattr(settings, key, default)
|
|
47
|
+
return _mcp_settings_cache[key]
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_max_sessions_per_server() -> int:
|
|
51
|
+
"""Get maximum number of sessions per server to prevent resource exhaustion."""
|
|
52
|
+
return _get_mcp_setting("mcp_max_sessions_per_server")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def get_session_idle_timeout() -> int:
|
|
56
|
+
"""Get 5 minutes idle timeout for sessions."""
|
|
57
|
+
return _get_mcp_setting("mcp_session_idle_timeout")
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def get_session_cleanup_interval() -> int:
|
|
61
|
+
"""Get cleanup interval in seconds."""
|
|
62
|
+
return _get_mcp_setting("mcp_session_cleanup_interval")
|
|
63
|
+
|
|
64
|
+
|
|
45
65
|
# RFC 7230 compliant header name pattern: token = 1*tchar
|
|
46
66
|
# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
|
47
67
|
# "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
|
@@ -65,6 +85,46 @@ ALLOWED_HEADERS = {
|
|
|
65
85
|
}
|
|
66
86
|
|
|
67
87
|
|
|
88
|
+
def create_mcp_http_client_with_ssl_option(
|
|
89
|
+
headers: dict[str, str] | None = None,
|
|
90
|
+
timeout: httpx.Timeout | None = None,
|
|
91
|
+
auth: httpx.Auth | None = None,
|
|
92
|
+
*,
|
|
93
|
+
verify_ssl: bool = True,
|
|
94
|
+
) -> httpx.AsyncClient:
|
|
95
|
+
"""Create an httpx AsyncClient with configurable SSL verification.
|
|
96
|
+
|
|
97
|
+
This is a custom factory that extends the standard MCP client factory
|
|
98
|
+
to support disabling SSL verification for self-signed certificates.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
headers: Optional headers to include with all requests.
|
|
102
|
+
timeout: Request timeout as httpx.Timeout object.
|
|
103
|
+
auth: Optional authentication handler.
|
|
104
|
+
verify_ssl: Whether to verify SSL certificates (default: True).
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Configured httpx.AsyncClient instance.
|
|
108
|
+
"""
|
|
109
|
+
kwargs: dict[str, Any] = {
|
|
110
|
+
"follow_redirects": True,
|
|
111
|
+
"verify": verify_ssl,
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if timeout is None:
|
|
115
|
+
kwargs["timeout"] = httpx.Timeout(30.0)
|
|
116
|
+
else:
|
|
117
|
+
kwargs["timeout"] = timeout
|
|
118
|
+
|
|
119
|
+
if headers is not None:
|
|
120
|
+
kwargs["headers"] = headers
|
|
121
|
+
|
|
122
|
+
if auth is not None:
|
|
123
|
+
kwargs["auth"] = auth
|
|
124
|
+
|
|
125
|
+
return httpx.AsyncClient(**kwargs)
|
|
126
|
+
|
|
127
|
+
|
|
68
128
|
def validate_headers(headers: dict[str, str]) -> dict[str, str]:
|
|
69
129
|
"""Validate and sanitize HTTP headers according to RFC 7230.
|
|
70
130
|
|
|
@@ -432,7 +492,7 @@ class MCPSessionManager:
|
|
|
432
492
|
"""Periodically clean up idle sessions."""
|
|
433
493
|
while True:
|
|
434
494
|
try:
|
|
435
|
-
await asyncio.sleep(
|
|
495
|
+
await asyncio.sleep(get_session_cleanup_interval())
|
|
436
496
|
await self._cleanup_idle_sessions()
|
|
437
497
|
except asyncio.CancelledError:
|
|
438
498
|
break
|
|
@@ -450,7 +510,7 @@ class MCPSessionManager:
|
|
|
450
510
|
sessions_to_remove = []
|
|
451
511
|
|
|
452
512
|
for session_id, session_info in list(sessions.items()):
|
|
453
|
-
if current_time - session_info["last_used"] >
|
|
513
|
+
if current_time - session_info["last_used"] > get_session_idle_timeout():
|
|
454
514
|
sessions_to_remove.append(session_id)
|
|
455
515
|
|
|
456
516
|
# Clean up idle sessions
|
|
@@ -573,7 +633,7 @@ class MCPSessionManager:
|
|
|
573
633
|
await self._cleanup_session_by_id(server_key, session_id)
|
|
574
634
|
|
|
575
635
|
# Check if we've reached the maximum number of sessions for this server
|
|
576
|
-
if len(sessions) >=
|
|
636
|
+
if len(sessions) >= get_max_sessions_per_server():
|
|
577
637
|
# Remove the oldest session
|
|
578
638
|
oldest_session_id = min(sessions.keys(), key=lambda x: sessions[x]["last_used"])
|
|
579
639
|
await logger.ainfo(
|
|
@@ -675,7 +735,7 @@ class MCPSessionManager:
|
|
|
675
735
|
|
|
676
736
|
Args:
|
|
677
737
|
session_id: Unique identifier for this session
|
|
678
|
-
connection_params: Connection parameters including URL, headers, timeouts
|
|
738
|
+
connection_params: Connection parameters including URL, headers, timeouts, verify_ssl
|
|
679
739
|
preferred_transport: If set to "sse", skip Streamable HTTP and go directly to SSE
|
|
680
740
|
|
|
681
741
|
Returns:
|
|
@@ -691,6 +751,19 @@ class MCPSessionManager:
|
|
|
691
751
|
# Track which transport succeeded
|
|
692
752
|
used_transport: list[str] = []
|
|
693
753
|
|
|
754
|
+
# Get verify_ssl option from connection params, default to True
|
|
755
|
+
verify_ssl = connection_params.get("verify_ssl", True)
|
|
756
|
+
|
|
757
|
+
# Create custom httpx client factory with SSL verification option
|
|
758
|
+
def custom_httpx_factory(
|
|
759
|
+
headers: dict[str, str] | None = None,
|
|
760
|
+
timeout: httpx.Timeout | None = None,
|
|
761
|
+
auth: httpx.Auth | None = None,
|
|
762
|
+
) -> httpx.AsyncClient:
|
|
763
|
+
return create_mcp_http_client_with_ssl_option(
|
|
764
|
+
headers=headers, timeout=timeout, auth=auth, verify_ssl=verify_ssl
|
|
765
|
+
)
|
|
766
|
+
|
|
694
767
|
async def session_task():
|
|
695
768
|
"""Background task that keeps the session alive."""
|
|
696
769
|
streamable_error = None
|
|
@@ -705,6 +778,7 @@ class MCPSessionManager:
|
|
|
705
778
|
url=connection_params["url"],
|
|
706
779
|
headers=connection_params["headers"],
|
|
707
780
|
timeout=connection_params["timeout_seconds"],
|
|
781
|
+
httpx_client_factory=custom_httpx_factory,
|
|
708
782
|
) as (read, write, _):
|
|
709
783
|
session = ClientSession(read, write)
|
|
710
784
|
async with session:
|
|
@@ -745,6 +819,7 @@ class MCPSessionManager:
|
|
|
745
819
|
connection_params["headers"],
|
|
746
820
|
connection_params["timeout_seconds"],
|
|
747
821
|
sse_read_timeout,
|
|
822
|
+
httpx_client_factory=custom_httpx_factory,
|
|
748
823
|
) as (read, write):
|
|
749
824
|
session = ClientSession(read, write)
|
|
750
825
|
async with session:
|
|
@@ -1196,6 +1271,8 @@ class MCPStreamableHttpClient:
|
|
|
1196
1271
|
headers: dict[str, str] | None = None,
|
|
1197
1272
|
timeout_seconds: int = 30,
|
|
1198
1273
|
sse_read_timeout_seconds: int = 30,
|
|
1274
|
+
*,
|
|
1275
|
+
verify_ssl: bool = True,
|
|
1199
1276
|
) -> list[StructuredTool]:
|
|
1200
1277
|
"""Connect to MCP server using Streamable HTTP transport with SSE fallback (SDK style)."""
|
|
1201
1278
|
# Validate and sanitize headers early
|
|
@@ -1213,12 +1290,13 @@ class MCPStreamableHttpClient:
|
|
|
1213
1290
|
msg = f"Invalid Streamable HTTP or SSE URL ({url}): {error_msg}"
|
|
1214
1291
|
raise ValueError(msg)
|
|
1215
1292
|
# Store connection parameters for later use in run_tool
|
|
1216
|
-
# Include SSE read timeout for fallback
|
|
1293
|
+
# Include SSE read timeout for fallback and SSL verification option
|
|
1217
1294
|
self._connection_params = {
|
|
1218
1295
|
"url": url,
|
|
1219
1296
|
"headers": validated_headers,
|
|
1220
1297
|
"timeout_seconds": timeout_seconds,
|
|
1221
1298
|
"sse_read_timeout_seconds": sse_read_timeout_seconds,
|
|
1299
|
+
"verify_ssl": verify_ssl,
|
|
1222
1300
|
}
|
|
1223
1301
|
elif headers:
|
|
1224
1302
|
self._connection_params["headers"] = validated_headers
|
|
@@ -1238,11 +1316,18 @@ class MCPStreamableHttpClient:
|
|
|
1238
1316
|
return response.tools
|
|
1239
1317
|
|
|
1240
1318
|
async def connect_to_server(
|
|
1241
|
-
self,
|
|
1319
|
+
self,
|
|
1320
|
+
url: str,
|
|
1321
|
+
headers: dict[str, str] | None = None,
|
|
1322
|
+
sse_read_timeout_seconds: int = 30,
|
|
1323
|
+
*,
|
|
1324
|
+
verify_ssl: bool = True,
|
|
1242
1325
|
) -> list[StructuredTool]:
|
|
1243
1326
|
"""Connect to MCP server using Streamable HTTP with SSE fallback transport (SDK style)."""
|
|
1244
1327
|
return await asyncio.wait_for(
|
|
1245
|
-
self._connect_to_server(
|
|
1328
|
+
self._connect_to_server(
|
|
1329
|
+
url, headers, sse_read_timeout_seconds=sse_read_timeout_seconds, verify_ssl=verify_ssl
|
|
1330
|
+
),
|
|
1246
1331
|
timeout=get_settings_service().settings.mcp_server_timeout,
|
|
1247
1332
|
)
|
|
1248
1333
|
|
|
@@ -1473,7 +1558,8 @@ async def update_tools(
|
|
|
1473
1558
|
client = mcp_stdio_client
|
|
1474
1559
|
elif mode in ["Streamable_HTTP", "SSE"]:
|
|
1475
1560
|
# Streamable HTTP connection with SSE fallback
|
|
1476
|
-
|
|
1561
|
+
verify_ssl = server_config.get("verify_ssl", True)
|
|
1562
|
+
tools = await mcp_streamable_http_client.connect_to_server(url, headers=headers, verify_ssl=verify_ssl)
|
|
1477
1563
|
client = mcp_streamable_http_client
|
|
1478
1564
|
else:
|
|
1479
1565
|
logger.error(f"Invalid MCP server mode for '{server_name}': {mode}")
|
|
@@ -14,14 +14,18 @@ class ModelProvidersDict(TypedDict):
|
|
|
14
14
|
is_active: bool
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
def get_filtered_inputs(component_class):
|
|
17
|
+
def get_filtered_inputs(component_class, provider_name: str | None = None):
|
|
18
18
|
base_input_names = {field.name for field in LCModelComponent.get_base_inputs()}
|
|
19
19
|
component_instance = component_class()
|
|
20
20
|
|
|
21
|
-
return [
|
|
21
|
+
return [
|
|
22
|
+
process_inputs(input_, provider_name)
|
|
23
|
+
for input_ in component_instance.inputs
|
|
24
|
+
if input_.name not in base_input_names
|
|
25
|
+
]
|
|
22
26
|
|
|
23
27
|
|
|
24
|
-
def process_inputs(component_data: Input):
|
|
28
|
+
def process_inputs(component_data: Input, provider_name: str | None = None):
|
|
25
29
|
"""Processes and modifies an input configuration based on its type or name.
|
|
26
30
|
|
|
27
31
|
Adjusts properties such as value, advanced status, real-time refresh, and additional information for specific
|
|
@@ -29,6 +33,7 @@ def process_inputs(component_data: Input):
|
|
|
29
33
|
|
|
30
34
|
Args:
|
|
31
35
|
component_data: The input configuration to process.
|
|
36
|
+
provider_name: The name of the provider to process the inputs for.
|
|
32
37
|
|
|
33
38
|
Returns:
|
|
34
39
|
The modified input configuration.
|
|
@@ -43,9 +48,11 @@ def process_inputs(component_data: Input):
|
|
|
43
48
|
component_data.advanced = True
|
|
44
49
|
component_data.value = True
|
|
45
50
|
elif component_data.name in {"temperature", "base_url"}:
|
|
46
|
-
|
|
51
|
+
if provider_name not in ["IBM watsonx.ai", "Ollama"]:
|
|
52
|
+
component_data = set_advanced_true(component_data)
|
|
47
53
|
elif component_data.name == "model_name":
|
|
48
|
-
|
|
54
|
+
if provider_name not in ["IBM watsonx.ai"]:
|
|
55
|
+
component_data = set_real_time_refresh_false(component_data)
|
|
49
56
|
component_data = add_combobox_true(component_data)
|
|
50
57
|
component_data = add_info(
|
|
51
58
|
component_data,
|
|
@@ -79,6 +86,28 @@ def create_input_fields_dict(inputs: list[Input], prefix: str) -> dict[str, Inpu
|
|
|
79
86
|
return {f"{prefix}{input_.name}": input_.to_dict() for input_ in inputs}
|
|
80
87
|
|
|
81
88
|
|
|
89
|
+
def _get_ollama_inputs_and_fields():
|
|
90
|
+
try:
|
|
91
|
+
from lfx.components.ollama.ollama import ChatOllamaComponent
|
|
92
|
+
|
|
93
|
+
ollama_inputs = get_filtered_inputs(ChatOllamaComponent, provider_name="Ollama")
|
|
94
|
+
except ImportError as e:
|
|
95
|
+
msg = "Ollama is not installed. Please install it with `pip install langchain-ollama`."
|
|
96
|
+
raise ImportError(msg) from e
|
|
97
|
+
return ollama_inputs, create_input_fields_dict(ollama_inputs, "")
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _get_watsonx_inputs_and_fields():
|
|
101
|
+
try:
|
|
102
|
+
from lfx.components.ibm.watsonx import WatsonxAIComponent
|
|
103
|
+
|
|
104
|
+
watsonx_inputs = get_filtered_inputs(WatsonxAIComponent, provider_name="IBM watsonx.ai")
|
|
105
|
+
except ImportError as e:
|
|
106
|
+
msg = "IBM watsonx.ai is not installed. Please install it with `pip install langchain-ibm-watsonx`."
|
|
107
|
+
raise ImportError(msg) from e
|
|
108
|
+
return watsonx_inputs, create_input_fields_dict(watsonx_inputs, "")
|
|
109
|
+
|
|
110
|
+
|
|
82
111
|
def _get_google_generative_ai_inputs_and_fields():
|
|
83
112
|
try:
|
|
84
113
|
from lfx.components.google.google_generative_ai import GoogleGenerativeAIComponent
|
|
@@ -293,6 +322,36 @@ try:
|
|
|
293
322
|
except ImportError:
|
|
294
323
|
pass
|
|
295
324
|
|
|
325
|
+
try:
|
|
326
|
+
from lfx.components.ibm.watsonx import WatsonxAIComponent
|
|
327
|
+
|
|
328
|
+
watsonx_inputs, watsonx_fields = _get_watsonx_inputs_and_fields()
|
|
329
|
+
MODEL_PROVIDERS_DICT["IBM watsonx.ai"] = {
|
|
330
|
+
"fields": watsonx_fields,
|
|
331
|
+
"inputs": watsonx_inputs,
|
|
332
|
+
"prefix": "",
|
|
333
|
+
"component_class": WatsonxAIComponent(),
|
|
334
|
+
"icon": WatsonxAIComponent.icon,
|
|
335
|
+
"is_active": True,
|
|
336
|
+
}
|
|
337
|
+
except ImportError:
|
|
338
|
+
pass
|
|
339
|
+
|
|
340
|
+
try:
|
|
341
|
+
from lfx.components.ollama.ollama import ChatOllamaComponent
|
|
342
|
+
|
|
343
|
+
ollama_inputs, ollama_fields = _get_ollama_inputs_and_fields()
|
|
344
|
+
MODEL_PROVIDERS_DICT["Ollama"] = {
|
|
345
|
+
"fields": ollama_fields,
|
|
346
|
+
"inputs": ollama_inputs,
|
|
347
|
+
"prefix": "",
|
|
348
|
+
"component_class": ChatOllamaComponent(),
|
|
349
|
+
"icon": ChatOllamaComponent.icon,
|
|
350
|
+
"is_active": True,
|
|
351
|
+
}
|
|
352
|
+
except ImportError:
|
|
353
|
+
pass
|
|
354
|
+
|
|
296
355
|
# Expose only active providers ----------------------------------------------
|
|
297
356
|
ACTIVE_MODEL_PROVIDERS_DICT: dict[str, ModelProvidersDict] = {
|
|
298
357
|
name: prov for name, prov in MODEL_PROVIDERS_DICT.items() if prov.get("is_active", True)
|
|
@@ -302,10 +361,18 @@ MODEL_PROVIDERS: list[str] = list(ACTIVE_MODEL_PROVIDERS_DICT.keys())
|
|
|
302
361
|
|
|
303
362
|
ALL_PROVIDER_FIELDS: list[str] = [field for prov in ACTIVE_MODEL_PROVIDERS_DICT.values() for field in prov["fields"]]
|
|
304
363
|
|
|
305
|
-
MODEL_DYNAMIC_UPDATE_FIELDS = [
|
|
364
|
+
MODEL_DYNAMIC_UPDATE_FIELDS = [
|
|
365
|
+
"api_key",
|
|
366
|
+
"model",
|
|
367
|
+
"tool_model_enabled",
|
|
368
|
+
"base_url",
|
|
369
|
+
"model_name",
|
|
370
|
+
"watsonx_endpoint",
|
|
371
|
+
"url",
|
|
372
|
+
]
|
|
306
373
|
|
|
307
374
|
MODELS_METADATA = {name: {"icon": prov["icon"]} for name, prov in ACTIVE_MODEL_PROVIDERS_DICT.items()}
|
|
308
375
|
|
|
309
|
-
MODEL_PROVIDERS_LIST = ["Anthropic", "Google Generative AI", "OpenAI"]
|
|
376
|
+
MODEL_PROVIDERS_LIST = ["Anthropic", "Google Generative AI", "OpenAI", "IBM watsonx.ai", "Ollama"]
|
|
310
377
|
|
|
311
378
|
MODEL_OPTIONS_METADATA = [MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST if key in MODELS_METADATA]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .model_metadata import create_model_metadata
|
|
2
|
+
|
|
3
|
+
# Granite Embedding models
|
|
4
|
+
WATSONX_EMBEDDING_MODELS_DETAILED = [
|
|
5
|
+
create_model_metadata(provider="IBM Watsonx", name="ibm/granite-embedding-125m-english", icon="IBMWatsonx"),
|
|
6
|
+
create_model_metadata(provider="IBM Watsonx", name="ibm/granite-embedding-278m-multilingual", icon="IBMWatsonx"),
|
|
7
|
+
create_model_metadata(provider="IBM Watsonx", name="ibm/granite-embedding-30m-english", icon="IBMWatsonx"),
|
|
8
|
+
create_model_metadata(provider="IBM Watsonx", name="ibm/granite-embedding-107m-multilingual", icon="IBMWatsonx"),
|
|
9
|
+
create_model_metadata(provider="IBM Watsonx", name="ibm/granite-embedding-30m-sparse", icon="IBMWatsonx"),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
WATSONX_EMBEDDING_MODEL_NAMES = [metadata["name"] for metadata in WATSONX_EMBEDDING_MODELS_DETAILED]
|
lfx/cli/commands.py
CHANGED
|
@@ -43,7 +43,7 @@ def serve_command(
|
|
|
43
43
|
host: str = typer.Option("127.0.0.1", "--host", "-h", help="Host to bind the server to"),
|
|
44
44
|
port: int = typer.Option(8000, "--port", "-p", help="Port to bind the server to"),
|
|
45
45
|
verbose: bool = typer.Option(False, "--verbose", "-v", help="Show diagnostic output and execution details"), # noqa: FBT001, FBT003
|
|
46
|
-
env_file: Path | None = typer.Option(
|
|
46
|
+
env_file: Path | None = typer.Option(
|
|
47
47
|
None,
|
|
48
48
|
"--env-file",
|
|
49
49
|
help="Path to the .env file containing environment variables",
|
|
@@ -6,6 +6,7 @@ from lfx.components._importing import import_mod
|
|
|
6
6
|
|
|
7
7
|
if TYPE_CHECKING:
|
|
8
8
|
from lfx.components.agents.agent import AgentComponent
|
|
9
|
+
from lfx.components.agents.altk_agent import ALTKAgentComponent
|
|
9
10
|
from lfx.components.agents.cuga_agent import CugaComponent
|
|
10
11
|
from lfx.components.agents.mcp_component import MCPToolsComponent
|
|
11
12
|
|
|
@@ -13,9 +14,10 @@ _dynamic_imports = {
|
|
|
13
14
|
"AgentComponent": "agent",
|
|
14
15
|
"CugaComponent": "cuga_agent",
|
|
15
16
|
"MCPToolsComponent": "mcp_component",
|
|
17
|
+
"ALTKAgentComponent": "altk_agent",
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
__all__ = ["AgentComponent", "CugaComponent", "MCPToolsComponent"]
|
|
20
|
+
__all__ = ["ALTKAgentComponent", "AgentComponent", "CugaComponent", "MCPToolsComponent"]
|
|
19
21
|
|
|
20
22
|
|
|
21
23
|
def __getattr__(attr_name: str) -> Any:
|
lfx/components/agents/agent.py
CHANGED
|
@@ -20,8 +20,8 @@ from lfx.components.langchain_utilities.tool_calling import ToolCallingAgentComp
|
|
|
20
20
|
from lfx.custom.custom_component.component import get_component_toolkit
|
|
21
21
|
from lfx.custom.utils import update_component_build_config
|
|
22
22
|
from lfx.helpers.base_model import build_model_from_schema
|
|
23
|
-
from lfx.inputs.inputs import BoolInput
|
|
24
|
-
from lfx.io import DropdownInput, IntInput, MultilineInput, Output, TableInput
|
|
23
|
+
from lfx.inputs.inputs import BoolInput, SecretStrInput, StrInput
|
|
24
|
+
from lfx.io import DropdownInput, IntInput, MessageTextInput, MultilineInput, Output, TableInput
|
|
25
25
|
from lfx.log.logger import logger
|
|
26
26
|
from lfx.schema.data import Data
|
|
27
27
|
from lfx.schema.dotdict import dotdict
|
|
@@ -77,6 +77,32 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
77
77
|
},
|
|
78
78
|
},
|
|
79
79
|
),
|
|
80
|
+
SecretStrInput(
|
|
81
|
+
name="api_key",
|
|
82
|
+
display_name="API Key",
|
|
83
|
+
info="The API key to use for the model.",
|
|
84
|
+
required=True,
|
|
85
|
+
),
|
|
86
|
+
StrInput(
|
|
87
|
+
name="base_url",
|
|
88
|
+
display_name="Base URL",
|
|
89
|
+
info="The base URL of the API.",
|
|
90
|
+
required=True,
|
|
91
|
+
show=False,
|
|
92
|
+
),
|
|
93
|
+
StrInput(
|
|
94
|
+
name="project_id",
|
|
95
|
+
display_name="Project ID",
|
|
96
|
+
info="The project ID of the model.",
|
|
97
|
+
required=True,
|
|
98
|
+
show=False,
|
|
99
|
+
),
|
|
100
|
+
IntInput(
|
|
101
|
+
name="max_output_tokens",
|
|
102
|
+
display_name="Max Output Tokens",
|
|
103
|
+
info="The maximum number of tokens to generate.",
|
|
104
|
+
show=False,
|
|
105
|
+
),
|
|
80
106
|
*openai_inputs_filtered,
|
|
81
107
|
MultilineInput(
|
|
82
108
|
name="system_prompt",
|
|
@@ -85,6 +111,13 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
85
111
|
value="You are a helpful assistant that can use tools to answer questions and perform tasks.",
|
|
86
112
|
advanced=False,
|
|
87
113
|
),
|
|
114
|
+
MessageTextInput(
|
|
115
|
+
name="context_id",
|
|
116
|
+
display_name="Context ID",
|
|
117
|
+
info="The context ID of the chat. Adds an extra layer to the local memory.",
|
|
118
|
+
value="",
|
|
119
|
+
advanced=True,
|
|
120
|
+
),
|
|
88
121
|
IntInput(
|
|
89
122
|
name="n_messages",
|
|
90
123
|
display_name="Number of Chat History Messages",
|
|
@@ -154,7 +187,7 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
154
187
|
},
|
|
155
188
|
],
|
|
156
189
|
),
|
|
157
|
-
*LCToolsAgentComponent.
|
|
190
|
+
*LCToolsAgentComponent.get_base_inputs(),
|
|
158
191
|
# removed memory inputs from agent component
|
|
159
192
|
# *memory_inputs,
|
|
160
193
|
BoolInput(
|
|
@@ -188,10 +221,15 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
188
221
|
if not isinstance(self.tools, list): # type: ignore[has-type]
|
|
189
222
|
self.tools = []
|
|
190
223
|
current_date_tool = (await CurrentDateComponent(**self.get_base_args()).to_toolkit()).pop(0)
|
|
224
|
+
|
|
191
225
|
if not isinstance(current_date_tool, StructuredTool):
|
|
192
226
|
msg = "CurrentDateComponent must be converted to a StructuredTool"
|
|
193
227
|
raise TypeError(msg)
|
|
194
228
|
self.tools.append(current_date_tool)
|
|
229
|
+
|
|
230
|
+
# Set shared callbacks for tracing the tools used by the agent
|
|
231
|
+
self.set_tools_callbacks(self.tools, self._get_shared_callbacks())
|
|
232
|
+
|
|
195
233
|
return llm_model, self.chat_history, self.tools
|
|
196
234
|
|
|
197
235
|
async def message_response(self) -> Message:
|
|
@@ -408,6 +446,7 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
408
446
|
await MemoryComponent(**self.get_base_args())
|
|
409
447
|
.set(
|
|
410
448
|
session_id=self.graph.session_id,
|
|
449
|
+
context_id=self.context_id,
|
|
411
450
|
order="Ascending",
|
|
412
451
|
n_messages=self.n_messages,
|
|
413
452
|
)
|
|
@@ -463,7 +502,8 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
463
502
|
def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:
|
|
464
503
|
"""Delete specified fields from build_config."""
|
|
465
504
|
for field in fields:
|
|
466
|
-
build_config
|
|
505
|
+
if build_config is not None and field in build_config:
|
|
506
|
+
build_config.pop(field, None)
|
|
467
507
|
|
|
468
508
|
def update_input_types(self, build_config: dotdict) -> dotdict:
|
|
469
509
|
"""Update input types for all fields in build_config."""
|
|
@@ -591,11 +631,14 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
591
631
|
agent_description = self.get_tool_description()
|
|
592
632
|
# TODO: Agent Description Depreciated Feature to be removed
|
|
593
633
|
description = f"{agent_description}{tools_names}"
|
|
634
|
+
|
|
594
635
|
tools = component_toolkit(component=self).get_tools(
|
|
595
636
|
tool_name="Call_Agent",
|
|
596
637
|
tool_description=description,
|
|
638
|
+
# here we do not use the shared callbacks as we are exposing the agent as a tool
|
|
597
639
|
callbacks=self.get_langchain_callbacks(),
|
|
598
640
|
)
|
|
599
641
|
if hasattr(self, "tools_metadata"):
|
|
600
642
|
tools = component_toolkit(component=self, metadata=self.tools_metadata).update_tools_metadata(tools=tools)
|
|
643
|
+
|
|
601
644
|
return tools
|