lfx-nightly 0.1.13.dev0__py3-none-any.whl → 0.2.0.dev26__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 +121 -29
- lfx/base/agents/altk_base_agent.py +380 -0
- lfx/base/agents/altk_tool_wrappers.py +565 -0
- lfx/base/agents/events.py +103 -35
- lfx/base/agents/utils.py +15 -2
- lfx/base/composio/composio_base.py +183 -233
- lfx/base/data/base_file.py +88 -21
- lfx/base/data/storage_utils.py +192 -0
- lfx/base/data/utils.py +178 -14
- lfx/base/datastax/__init__.py +5 -0
- lfx/{components/vectorstores/astradb.py → base/datastax/astradb_base.py} +84 -473
- lfx/base/embeddings/embeddings_class.py +113 -0
- lfx/base/io/chat.py +5 -4
- lfx/base/mcp/util.py +101 -15
- 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_input_constants.py +74 -7
- lfx/base/models/model_utils.py +100 -0
- lfx/base/models/ollama_constants.py +3 -0
- lfx/base/models/openai_constants.py +7 -0
- lfx/base/models/watsonx_constants.py +36 -0
- lfx/base/tools/run_flow.py +601 -129
- lfx/cli/commands.py +7 -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/altk/__init__.py +34 -0
- lfx/components/altk/altk_agent.py +193 -0
- lfx/components/amazon/amazon_bedrock_converse.py +1 -1
- lfx/components/apify/apify_actor.py +4 -4
- 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/{agents → cuga}/__init__.py +5 -7
- 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/__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 +6 -32
- lfx/components/datastax/astradb_graph.py +10 -124
- lfx/components/datastax/astradb_tool.py +13 -53
- lfx/components/datastax/astradb_vectorstore.py +134 -977
- 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/hcd.py +1 -1
- lfx/components/datastax/list_assistants.py +1 -0
- lfx/components/datastax/run.py +1 -0
- lfx/components/deactivated/json_document_builder.py +1 -1
- lfx/components/elastic/elasticsearch.py +1 -1
- lfx/components/elastic/opensearch_multimodal.py +1575 -0
- 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 +246 -18
- lfx/components/{knowledge_bases → files_and_knowledge}/ingestion.py +17 -9
- lfx/components/{knowledge_bases → files_and_knowledge}/retrieval.py +18 -10
- lfx/components/{data → files_and_knowledge}/save_file.py +142 -22
- 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 +47 -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 +25 -21
- lfx/components/input_output/__init__.py +3 -1
- lfx/components/input_output/chat.py +12 -3
- lfx/components/input_output/chat_output.py +12 -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 +1 -1
- 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 +56 -18
- lfx/components/logic/__init__.py +126 -0
- lfx/components/mem0/mem0_chat_memory.py +11 -0
- lfx/components/mistral/mistral_embeddings.py +1 -1
- lfx/components/models/__init__.py +64 -9
- lfx/components/models_and_agents/__init__.py +49 -0
- lfx/components/{agents → models_and_agents}/agent.py +49 -6
- lfx/components/models_and_agents/embedding_model.py +423 -0
- lfx/components/models_and_agents/language_model.py +398 -0
- lfx/components/{agents → models_and_agents}/mcp_component.py +84 -45
- 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 +235 -14
- lfx/components/openrouter/openrouter.py +49 -147
- lfx/components/processing/__init__.py +9 -57
- 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 +7 -2
- 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/__init__.py +0 -6
- lfx/components/vectorstores/local_db.py +9 -0
- lfx/components/youtube/youtube_transcripts.py +118 -30
- lfx/custom/custom_component/component.py +60 -3
- lfx/custom/custom_component/custom_component.py +68 -6
- lfx/field_typing/constants.py +1 -0
- lfx/graph/edge/base.py +45 -22
- lfx/graph/graph/base.py +5 -2
- lfx/graph/graph/schema.py +3 -2
- lfx/graph/state/model.py +15 -2
- lfx/graph/utils.py +6 -0
- lfx/graph/vertex/base.py +4 -1
- lfx/graph/vertex/param_handler.py +10 -7
- lfx/graph/vertex/vertex_types.py +1 -1
- 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/io/schema.py +6 -0
- lfx/log/logger.py +5 -3
- lfx/schema/schema.py +5 -0
- lfx/services/database/__init__.py +5 -0
- lfx/services/database/service.py +25 -0
- lfx/services/deps.py +87 -22
- lfx/services/manager.py +19 -6
- lfx/services/mcp_composer/service.py +998 -157
- lfx/services/session.py +5 -0
- lfx/services/settings/base.py +51 -7
- lfx/services/settings/constants.py +8 -0
- lfx/services/storage/local.py +76 -46
- lfx/services/storage/service.py +152 -29
- lfx/template/field/base.py +3 -0
- lfx/utils/ssrf_protection.py +384 -0
- lfx/utils/validate_cloud.py +26 -0
- {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/METADATA +38 -22
- {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/RECORD +210 -196
- {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/WHEEL +1 -1
- lfx/components/agents/cuga_agent.py +0 -1013
- lfx/components/datastax/astra_db.py +0 -77
- lfx/components/datastax/cassandra.py +0 -92
- lfx/components/logic/run_flow.py +0 -71
- lfx/components/models/embedding_model.py +0 -114
- lfx/components/models/language_model.py +0 -144
- 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/{data → data_source}/mock_data.py +0 -0
- /lfx/components/datastax/{astra_vectorize.py → astradb_vectorize.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.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
import requests
|
|
4
|
+
from langchain_anthropic import ChatAnthropic
|
|
5
|
+
from langchain_ibm import ChatWatsonx
|
|
6
|
+
from langchain_ollama import ChatOllama
|
|
7
|
+
from langchain_openai import ChatOpenAI
|
|
8
|
+
from pydantic.v1 import SecretStr
|
|
9
|
+
|
|
10
|
+
from lfx.base.models.anthropic_constants import ANTHROPIC_MODELS
|
|
11
|
+
from lfx.base.models.google_generative_ai_constants import GOOGLE_GENERATIVE_AI_MODELS
|
|
12
|
+
from lfx.base.models.google_generative_ai_model import ChatGoogleGenerativeAIFixed
|
|
13
|
+
from lfx.base.models.model import LCModelComponent
|
|
14
|
+
from lfx.base.models.model_utils import get_ollama_models, is_valid_ollama_url
|
|
15
|
+
from lfx.base.models.openai_constants import OPENAI_CHAT_MODEL_NAMES, OPENAI_REASONING_MODEL_NAMES
|
|
16
|
+
from lfx.field_typing import LanguageModel
|
|
17
|
+
from lfx.field_typing.range_spec import RangeSpec
|
|
18
|
+
from lfx.inputs.inputs import BoolInput, MessageTextInput, StrInput
|
|
19
|
+
from lfx.io import DropdownInput, MessageInput, MultilineInput, SecretStrInput, SliderInput
|
|
20
|
+
from lfx.log.logger import logger
|
|
21
|
+
from lfx.schema.dotdict import dotdict
|
|
22
|
+
from lfx.utils.util import transform_localhost_url
|
|
23
|
+
|
|
24
|
+
# IBM watsonx.ai constants
|
|
25
|
+
IBM_WATSONX_DEFAULT_MODELS = ["ibm/granite-3-2b-instruct", "ibm/granite-3-8b-instruct", "ibm/granite-13b-instruct-v2"]
|
|
26
|
+
IBM_WATSONX_URLS = [
|
|
27
|
+
"https://us-south.ml.cloud.ibm.com",
|
|
28
|
+
"https://eu-de.ml.cloud.ibm.com",
|
|
29
|
+
"https://eu-gb.ml.cloud.ibm.com",
|
|
30
|
+
"https://au-syd.ml.cloud.ibm.com",
|
|
31
|
+
"https://jp-tok.ml.cloud.ibm.com",
|
|
32
|
+
"https://ca-tor.ml.cloud.ibm.com",
|
|
33
|
+
]
|
|
34
|
+
|
|
35
|
+
# Ollama API constants
|
|
36
|
+
HTTP_STATUS_OK = 200
|
|
37
|
+
JSON_MODELS_KEY = "models"
|
|
38
|
+
JSON_NAME_KEY = "name"
|
|
39
|
+
JSON_CAPABILITIES_KEY = "capabilities"
|
|
40
|
+
DESIRED_CAPABILITY = "completion"
|
|
41
|
+
DEFAULT_OLLAMA_URL = "http://localhost:11434"
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class LanguageModelComponent(LCModelComponent):
|
|
45
|
+
display_name = "Language Model"
|
|
46
|
+
description = "Runs a language model given a specified provider."
|
|
47
|
+
documentation: str = "https://docs.langflow.org/components-models"
|
|
48
|
+
icon = "brain-circuit"
|
|
49
|
+
category = "models"
|
|
50
|
+
priority = 0 # Set priority to 0 to make it appear first
|
|
51
|
+
|
|
52
|
+
@staticmethod
|
|
53
|
+
def fetch_ibm_models(base_url: str) -> list[str]:
|
|
54
|
+
"""Fetch available models from the watsonx.ai API."""
|
|
55
|
+
try:
|
|
56
|
+
endpoint = f"{base_url}/ml/v1/foundation_model_specs"
|
|
57
|
+
params = {"version": "2024-09-16", "filters": "function_text_chat,!lifecycle_withdrawn"}
|
|
58
|
+
response = requests.get(endpoint, params=params, timeout=10)
|
|
59
|
+
response.raise_for_status()
|
|
60
|
+
data = response.json()
|
|
61
|
+
models = [model["model_id"] for model in data.get("resources", [])]
|
|
62
|
+
return sorted(models)
|
|
63
|
+
except Exception: # noqa: BLE001
|
|
64
|
+
logger.exception("Error fetching IBM watsonx models. Using default models.")
|
|
65
|
+
return IBM_WATSONX_DEFAULT_MODELS
|
|
66
|
+
|
|
67
|
+
inputs = [
|
|
68
|
+
DropdownInput(
|
|
69
|
+
name="provider",
|
|
70
|
+
display_name="Model Provider",
|
|
71
|
+
options=["OpenAI", "Anthropic", "Google", "IBM watsonx.ai", "Ollama"],
|
|
72
|
+
value="OpenAI",
|
|
73
|
+
info="Select the model provider",
|
|
74
|
+
real_time_refresh=True,
|
|
75
|
+
options_metadata=[
|
|
76
|
+
{"icon": "OpenAI"},
|
|
77
|
+
{"icon": "Anthropic"},
|
|
78
|
+
{"icon": "GoogleGenerativeAI"},
|
|
79
|
+
{"icon": "WatsonxAI"},
|
|
80
|
+
{"icon": "Ollama"},
|
|
81
|
+
],
|
|
82
|
+
),
|
|
83
|
+
DropdownInput(
|
|
84
|
+
name="model_name",
|
|
85
|
+
display_name="Model Name",
|
|
86
|
+
options=OPENAI_CHAT_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES,
|
|
87
|
+
value=OPENAI_CHAT_MODEL_NAMES[0],
|
|
88
|
+
info="Select the model to use",
|
|
89
|
+
real_time_refresh=True,
|
|
90
|
+
refresh_button=True,
|
|
91
|
+
),
|
|
92
|
+
SecretStrInput(
|
|
93
|
+
name="api_key",
|
|
94
|
+
display_name="OpenAI API Key",
|
|
95
|
+
info="Model Provider API key",
|
|
96
|
+
required=False,
|
|
97
|
+
show=True,
|
|
98
|
+
real_time_refresh=True,
|
|
99
|
+
),
|
|
100
|
+
DropdownInput(
|
|
101
|
+
name="base_url_ibm_watsonx",
|
|
102
|
+
display_name="watsonx API Endpoint",
|
|
103
|
+
info="The base URL of the API (IBM watsonx.ai only)",
|
|
104
|
+
options=IBM_WATSONX_URLS,
|
|
105
|
+
value=IBM_WATSONX_URLS[0],
|
|
106
|
+
show=False,
|
|
107
|
+
real_time_refresh=True,
|
|
108
|
+
),
|
|
109
|
+
StrInput(
|
|
110
|
+
name="project_id",
|
|
111
|
+
display_name="watsonx Project ID",
|
|
112
|
+
info="The project ID associated with the foundation model (IBM watsonx.ai only)",
|
|
113
|
+
show=False,
|
|
114
|
+
required=False,
|
|
115
|
+
),
|
|
116
|
+
MessageTextInput(
|
|
117
|
+
name="ollama_base_url",
|
|
118
|
+
display_name="Ollama API URL",
|
|
119
|
+
info=f"Endpoint of the Ollama API (Ollama only). Defaults to {DEFAULT_OLLAMA_URL}",
|
|
120
|
+
value=DEFAULT_OLLAMA_URL,
|
|
121
|
+
show=False,
|
|
122
|
+
real_time_refresh=True,
|
|
123
|
+
load_from_db=True,
|
|
124
|
+
),
|
|
125
|
+
MessageInput(
|
|
126
|
+
name="input_value",
|
|
127
|
+
display_name="Input",
|
|
128
|
+
info="The input text to send to the model",
|
|
129
|
+
),
|
|
130
|
+
MultilineInput(
|
|
131
|
+
name="system_message",
|
|
132
|
+
display_name="System Message",
|
|
133
|
+
info="A system message that helps set the behavior of the assistant",
|
|
134
|
+
advanced=False,
|
|
135
|
+
),
|
|
136
|
+
BoolInput(
|
|
137
|
+
name="stream",
|
|
138
|
+
display_name="Stream",
|
|
139
|
+
info="Whether to stream the response",
|
|
140
|
+
value=False,
|
|
141
|
+
advanced=True,
|
|
142
|
+
),
|
|
143
|
+
SliderInput(
|
|
144
|
+
name="temperature",
|
|
145
|
+
display_name="Temperature",
|
|
146
|
+
value=0.1,
|
|
147
|
+
info="Controls randomness in responses",
|
|
148
|
+
range_spec=RangeSpec(min=0, max=1, step=0.01),
|
|
149
|
+
advanced=True,
|
|
150
|
+
),
|
|
151
|
+
]
|
|
152
|
+
|
|
153
|
+
def build_model(self) -> LanguageModel:
|
|
154
|
+
provider = self.provider
|
|
155
|
+
model_name = self.model_name
|
|
156
|
+
temperature = self.temperature
|
|
157
|
+
stream = self.stream
|
|
158
|
+
|
|
159
|
+
if provider == "OpenAI":
|
|
160
|
+
if not self.api_key:
|
|
161
|
+
msg = "OpenAI API key is required when using OpenAI provider"
|
|
162
|
+
raise ValueError(msg)
|
|
163
|
+
|
|
164
|
+
if model_name in OPENAI_REASONING_MODEL_NAMES:
|
|
165
|
+
# reasoning models do not support temperature (yet)
|
|
166
|
+
temperature = None
|
|
167
|
+
|
|
168
|
+
return ChatOpenAI(
|
|
169
|
+
model_name=model_name,
|
|
170
|
+
temperature=temperature,
|
|
171
|
+
streaming=stream,
|
|
172
|
+
openai_api_key=self.api_key,
|
|
173
|
+
)
|
|
174
|
+
if provider == "Anthropic":
|
|
175
|
+
if not self.api_key:
|
|
176
|
+
msg = "Anthropic API key is required when using Anthropic provider"
|
|
177
|
+
raise ValueError(msg)
|
|
178
|
+
return ChatAnthropic(
|
|
179
|
+
model=model_name,
|
|
180
|
+
temperature=temperature,
|
|
181
|
+
streaming=stream,
|
|
182
|
+
anthropic_api_key=self.api_key,
|
|
183
|
+
)
|
|
184
|
+
if provider == "Google":
|
|
185
|
+
if not self.api_key:
|
|
186
|
+
msg = "Google API key is required when using Google provider"
|
|
187
|
+
raise ValueError(msg)
|
|
188
|
+
return ChatGoogleGenerativeAIFixed(
|
|
189
|
+
model=model_name,
|
|
190
|
+
temperature=temperature,
|
|
191
|
+
streaming=stream,
|
|
192
|
+
google_api_key=self.api_key,
|
|
193
|
+
)
|
|
194
|
+
if provider == "IBM watsonx.ai":
|
|
195
|
+
if not self.api_key:
|
|
196
|
+
msg = "IBM API key is required when using IBM watsonx.ai provider"
|
|
197
|
+
raise ValueError(msg)
|
|
198
|
+
if not self.base_url_ibm_watsonx:
|
|
199
|
+
msg = "IBM watsonx API Endpoint is required when using IBM watsonx.ai provider"
|
|
200
|
+
raise ValueError(msg)
|
|
201
|
+
if not self.project_id:
|
|
202
|
+
msg = "IBM watsonx Project ID is required when using IBM watsonx.ai provider"
|
|
203
|
+
raise ValueError(msg)
|
|
204
|
+
return ChatWatsonx(
|
|
205
|
+
apikey=SecretStr(self.api_key).get_secret_value(),
|
|
206
|
+
url=self.base_url_ibm_watsonx,
|
|
207
|
+
project_id=self.project_id,
|
|
208
|
+
model_id=model_name,
|
|
209
|
+
params={
|
|
210
|
+
"temperature": temperature,
|
|
211
|
+
},
|
|
212
|
+
streaming=stream,
|
|
213
|
+
)
|
|
214
|
+
if provider == "Ollama":
|
|
215
|
+
if not self.ollama_base_url:
|
|
216
|
+
msg = "Ollama API URL is required when using Ollama provider"
|
|
217
|
+
raise ValueError(msg)
|
|
218
|
+
if not model_name:
|
|
219
|
+
msg = "Model name is required when using Ollama provider"
|
|
220
|
+
raise ValueError(msg)
|
|
221
|
+
|
|
222
|
+
transformed_base_url = transform_localhost_url(self.ollama_base_url)
|
|
223
|
+
|
|
224
|
+
# Check if URL contains /v1 suffix (OpenAI-compatible mode)
|
|
225
|
+
if transformed_base_url and transformed_base_url.rstrip("/").endswith("/v1"):
|
|
226
|
+
# Strip /v1 suffix and log warning
|
|
227
|
+
transformed_base_url = transformed_base_url.rstrip("/").removesuffix("/v1")
|
|
228
|
+
logger.warning(
|
|
229
|
+
"Detected '/v1' suffix in base URL. The Ollama component uses the native Ollama API, "
|
|
230
|
+
"not the OpenAI-compatible API. The '/v1' suffix has been automatically removed. "
|
|
231
|
+
"If you want to use the OpenAI-compatible API, please use the OpenAI component instead. "
|
|
232
|
+
"Learn more at https://docs.ollama.com/openai#openai-compatibility"
|
|
233
|
+
)
|
|
234
|
+
|
|
235
|
+
return ChatOllama(
|
|
236
|
+
base_url=transformed_base_url,
|
|
237
|
+
model=model_name,
|
|
238
|
+
temperature=temperature,
|
|
239
|
+
)
|
|
240
|
+
msg = f"Unknown provider: {provider}"
|
|
241
|
+
raise ValueError(msg)
|
|
242
|
+
|
|
243
|
+
async def update_build_config(
|
|
244
|
+
self, build_config: dotdict, field_value: Any, field_name: str | None = None
|
|
245
|
+
) -> dotdict:
|
|
246
|
+
if field_name == "provider":
|
|
247
|
+
if field_value == "OpenAI":
|
|
248
|
+
build_config["model_name"]["options"] = OPENAI_CHAT_MODEL_NAMES + OPENAI_REASONING_MODEL_NAMES
|
|
249
|
+
build_config["model_name"]["value"] = OPENAI_CHAT_MODEL_NAMES[0]
|
|
250
|
+
build_config["api_key"]["display_name"] = "OpenAI API Key"
|
|
251
|
+
build_config["api_key"]["show"] = True
|
|
252
|
+
build_config["base_url_ibm_watsonx"]["show"] = False
|
|
253
|
+
build_config["project_id"]["show"] = False
|
|
254
|
+
build_config["ollama_base_url"]["show"] = False
|
|
255
|
+
elif field_value == "Anthropic":
|
|
256
|
+
build_config["model_name"]["options"] = ANTHROPIC_MODELS
|
|
257
|
+
build_config["model_name"]["value"] = ANTHROPIC_MODELS[0]
|
|
258
|
+
build_config["api_key"]["display_name"] = "Anthropic API Key"
|
|
259
|
+
build_config["api_key"]["show"] = True
|
|
260
|
+
build_config["base_url_ibm_watsonx"]["show"] = False
|
|
261
|
+
build_config["project_id"]["show"] = False
|
|
262
|
+
build_config["ollama_base_url"]["show"] = False
|
|
263
|
+
elif field_value == "Google":
|
|
264
|
+
build_config["model_name"]["options"] = GOOGLE_GENERATIVE_AI_MODELS
|
|
265
|
+
build_config["model_name"]["value"] = GOOGLE_GENERATIVE_AI_MODELS[0]
|
|
266
|
+
build_config["api_key"]["display_name"] = "Google API Key"
|
|
267
|
+
build_config["api_key"]["show"] = True
|
|
268
|
+
build_config["base_url_ibm_watsonx"]["show"] = False
|
|
269
|
+
build_config["project_id"]["show"] = False
|
|
270
|
+
build_config["ollama_base_url"]["show"] = False
|
|
271
|
+
elif field_value == "IBM watsonx.ai":
|
|
272
|
+
build_config["model_name"]["options"] = IBM_WATSONX_DEFAULT_MODELS
|
|
273
|
+
build_config["model_name"]["value"] = IBM_WATSONX_DEFAULT_MODELS[0]
|
|
274
|
+
build_config["api_key"]["display_name"] = "IBM API Key"
|
|
275
|
+
build_config["api_key"]["show"] = True
|
|
276
|
+
build_config["base_url_ibm_watsonx"]["show"] = True
|
|
277
|
+
build_config["project_id"]["show"] = True
|
|
278
|
+
build_config["ollama_base_url"]["show"] = False
|
|
279
|
+
elif field_value == "Ollama":
|
|
280
|
+
# Fetch Ollama models from the API
|
|
281
|
+
build_config["api_key"]["show"] = False
|
|
282
|
+
build_config["base_url_ibm_watsonx"]["show"] = False
|
|
283
|
+
build_config["project_id"]["show"] = False
|
|
284
|
+
build_config["ollama_base_url"]["show"] = True
|
|
285
|
+
|
|
286
|
+
# Try multiple sources to get the URL (in order of preference):
|
|
287
|
+
# 1. Instance attribute (already resolved from global/db)
|
|
288
|
+
# 2. Build config value (may be a global variable reference)
|
|
289
|
+
# 3. Default value
|
|
290
|
+
ollama_url = getattr(self, "ollama_base_url", None)
|
|
291
|
+
if not ollama_url:
|
|
292
|
+
config_value = build_config["ollama_base_url"].get("value", DEFAULT_OLLAMA_URL)
|
|
293
|
+
# If config_value looks like a variable name (all caps with underscores), use default
|
|
294
|
+
is_variable_ref = (
|
|
295
|
+
config_value
|
|
296
|
+
and isinstance(config_value, str)
|
|
297
|
+
and config_value.isupper()
|
|
298
|
+
and "_" in config_value
|
|
299
|
+
)
|
|
300
|
+
if is_variable_ref:
|
|
301
|
+
await logger.adebug(
|
|
302
|
+
f"Config value appears to be a variable reference: {config_value}, using default"
|
|
303
|
+
)
|
|
304
|
+
ollama_url = DEFAULT_OLLAMA_URL
|
|
305
|
+
else:
|
|
306
|
+
ollama_url = config_value
|
|
307
|
+
|
|
308
|
+
await logger.adebug(f"Fetching Ollama models for provider switch. URL: {ollama_url}")
|
|
309
|
+
if await is_valid_ollama_url(url=ollama_url):
|
|
310
|
+
try:
|
|
311
|
+
models = await get_ollama_models(
|
|
312
|
+
base_url_value=ollama_url,
|
|
313
|
+
desired_capability=DESIRED_CAPABILITY,
|
|
314
|
+
json_models_key=JSON_MODELS_KEY,
|
|
315
|
+
json_name_key=JSON_NAME_KEY,
|
|
316
|
+
json_capabilities_key=JSON_CAPABILITIES_KEY,
|
|
317
|
+
)
|
|
318
|
+
build_config["model_name"]["options"] = models
|
|
319
|
+
build_config["model_name"]["value"] = models[0] if models else ""
|
|
320
|
+
except ValueError:
|
|
321
|
+
await logger.awarning("Failed to fetch Ollama models. Setting empty options.")
|
|
322
|
+
build_config["model_name"]["options"] = []
|
|
323
|
+
build_config["model_name"]["value"] = ""
|
|
324
|
+
else:
|
|
325
|
+
await logger.awarning(f"Invalid Ollama URL: {ollama_url}")
|
|
326
|
+
build_config["model_name"]["options"] = []
|
|
327
|
+
build_config["model_name"]["value"] = ""
|
|
328
|
+
elif (
|
|
329
|
+
field_name == "base_url_ibm_watsonx"
|
|
330
|
+
and field_value
|
|
331
|
+
and hasattr(self, "provider")
|
|
332
|
+
and self.provider == "IBM watsonx.ai"
|
|
333
|
+
):
|
|
334
|
+
# Fetch IBM models when base_url changes
|
|
335
|
+
try:
|
|
336
|
+
models = self.fetch_ibm_models(base_url=field_value)
|
|
337
|
+
build_config["model_name"]["options"] = models
|
|
338
|
+
build_config["model_name"]["value"] = models[0] if models else IBM_WATSONX_DEFAULT_MODELS[0]
|
|
339
|
+
info_message = f"Updated model options: {len(models)} models found in {field_value}"
|
|
340
|
+
logger.info(info_message)
|
|
341
|
+
except Exception: # noqa: BLE001
|
|
342
|
+
logger.exception("Error updating IBM model options.")
|
|
343
|
+
elif field_name == "ollama_base_url":
|
|
344
|
+
# Fetch Ollama models when ollama_base_url changes
|
|
345
|
+
# Use the field_value directly since this is triggered when the field changes
|
|
346
|
+
logger.debug(
|
|
347
|
+
f"Fetching Ollama models from updated URL: {build_config['ollama_base_url']} \
|
|
348
|
+
and value {self.ollama_base_url}",
|
|
349
|
+
)
|
|
350
|
+
await logger.adebug(f"Fetching Ollama models from updated URL: {self.ollama_base_url}")
|
|
351
|
+
if await is_valid_ollama_url(url=self.ollama_base_url):
|
|
352
|
+
try:
|
|
353
|
+
models = await get_ollama_models(
|
|
354
|
+
base_url_value=self.ollama_base_url,
|
|
355
|
+
desired_capability=DESIRED_CAPABILITY,
|
|
356
|
+
json_models_key=JSON_MODELS_KEY,
|
|
357
|
+
json_name_key=JSON_NAME_KEY,
|
|
358
|
+
json_capabilities_key=JSON_CAPABILITIES_KEY,
|
|
359
|
+
)
|
|
360
|
+
build_config["model_name"]["options"] = models
|
|
361
|
+
build_config["model_name"]["value"] = models[0] if models else ""
|
|
362
|
+
info_message = f"Updated model options: {len(models)} models found in {self.ollama_base_url}"
|
|
363
|
+
await logger.ainfo(info_message)
|
|
364
|
+
except ValueError:
|
|
365
|
+
await logger.awarning("Error updating Ollama model options.")
|
|
366
|
+
build_config["model_name"]["options"] = []
|
|
367
|
+
build_config["model_name"]["value"] = ""
|
|
368
|
+
else:
|
|
369
|
+
await logger.awarning(f"Invalid Ollama URL: {self.ollama_base_url}")
|
|
370
|
+
build_config["model_name"]["options"] = []
|
|
371
|
+
build_config["model_name"]["value"] = ""
|
|
372
|
+
elif field_name == "model_name":
|
|
373
|
+
# Refresh Ollama models when model_name field is accessed
|
|
374
|
+
if hasattr(self, "provider") and self.provider == "Ollama":
|
|
375
|
+
ollama_url = getattr(self, "ollama_base_url", DEFAULT_OLLAMA_URL)
|
|
376
|
+
if await is_valid_ollama_url(url=ollama_url):
|
|
377
|
+
try:
|
|
378
|
+
models = await get_ollama_models(
|
|
379
|
+
base_url_value=ollama_url,
|
|
380
|
+
desired_capability=DESIRED_CAPABILITY,
|
|
381
|
+
json_models_key=JSON_MODELS_KEY,
|
|
382
|
+
json_name_key=JSON_NAME_KEY,
|
|
383
|
+
json_capabilities_key=JSON_CAPABILITIES_KEY,
|
|
384
|
+
)
|
|
385
|
+
build_config["model_name"]["options"] = models
|
|
386
|
+
except ValueError:
|
|
387
|
+
await logger.awarning("Failed to refresh Ollama models.")
|
|
388
|
+
build_config["model_name"]["options"] = []
|
|
389
|
+
else:
|
|
390
|
+
build_config["model_name"]["options"] = []
|
|
391
|
+
|
|
392
|
+
# Hide system_message for o1 models - currently unsupported
|
|
393
|
+
if field_value and field_value.startswith("o1") and hasattr(self, "provider") and self.provider == "OpenAI":
|
|
394
|
+
if "system_message" in build_config:
|
|
395
|
+
build_config["system_message"]["show"] = False
|
|
396
|
+
elif "system_message" in build_config:
|
|
397
|
+
build_config["system_message"]["show"] = True
|
|
398
|
+
return build_config
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import json
|
|
4
5
|
import uuid
|
|
5
|
-
from typing import Any
|
|
6
6
|
|
|
7
7
|
from langchain_core.tools import StructuredTool # noqa: TC002
|
|
8
8
|
|
|
@@ -61,11 +61,12 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
61
61
|
"mcp_server",
|
|
62
62
|
"tool",
|
|
63
63
|
"use_cache",
|
|
64
|
+
"verify_ssl",
|
|
64
65
|
]
|
|
65
66
|
|
|
66
67
|
display_name = "MCP Tools"
|
|
67
68
|
description = "Connect to an MCP server to use its tools."
|
|
68
|
-
documentation: str = "https://docs.langflow.org/mcp-
|
|
69
|
+
documentation: str = "https://docs.langflow.org/mcp-tools"
|
|
69
70
|
icon = "Mcp"
|
|
70
71
|
name = "MCPTools"
|
|
71
72
|
|
|
@@ -86,6 +87,16 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
86
87
|
value=False,
|
|
87
88
|
advanced=True,
|
|
88
89
|
),
|
|
90
|
+
BoolInput(
|
|
91
|
+
name="verify_ssl",
|
|
92
|
+
display_name="Verify SSL Certificate",
|
|
93
|
+
info=(
|
|
94
|
+
"Enable SSL certificate verification for HTTPS connections. "
|
|
95
|
+
"Disable only for development/testing with self-signed certificates."
|
|
96
|
+
),
|
|
97
|
+
value=True,
|
|
98
|
+
advanced=True,
|
|
99
|
+
),
|
|
89
100
|
DropdownInput(
|
|
90
101
|
name="tool",
|
|
91
102
|
display_name="Tool",
|
|
@@ -210,6 +221,11 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
210
221
|
self.tools = []
|
|
211
222
|
return [], {"name": server_name, "config": server_config}
|
|
212
223
|
|
|
224
|
+
# Add verify_ssl option to server config if not present
|
|
225
|
+
if "verify_ssl" not in server_config:
|
|
226
|
+
verify_ssl = getattr(self, "verify_ssl", True)
|
|
227
|
+
server_config["verify_ssl"] = verify_ssl
|
|
228
|
+
|
|
213
229
|
_, tool_list, tool_cache = await update_tools(
|
|
214
230
|
server_name=server_name,
|
|
215
231
|
server_config=server_config,
|
|
@@ -308,9 +324,29 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
308
324
|
|
|
309
325
|
current_server_name = field_value.get("name") if isinstance(field_value, dict) else field_value
|
|
310
326
|
_last_selected_server = safe_cache_get(self._shared_component_cache, "last_selected_server", "")
|
|
327
|
+
server_changed = current_server_name != _last_selected_server
|
|
328
|
+
|
|
329
|
+
# Determine if "Tool Mode" is active by checking if the tool dropdown is hidden.
|
|
330
|
+
is_in_tool_mode = build_config["tools_metadata"]["show"]
|
|
331
|
+
|
|
332
|
+
# Get use_cache setting to determine if we should use cached data
|
|
333
|
+
use_cache = getattr(self, "use_cache", False)
|
|
334
|
+
|
|
335
|
+
# Fast path: if server didn't change and we already have options, keep them as-is
|
|
336
|
+
# BUT only if caching is enabled or we're in tool mode
|
|
337
|
+
existing_options = build_config.get("tool", {}).get("options") or []
|
|
338
|
+
if not server_changed and existing_options:
|
|
339
|
+
# In non-tool mode with cache disabled, skip the fast path to force refresh
|
|
340
|
+
if not is_in_tool_mode and not use_cache:
|
|
341
|
+
pass # Continue to refresh logic below
|
|
342
|
+
else:
|
|
343
|
+
if not is_in_tool_mode:
|
|
344
|
+
build_config["tool"]["show"] = True
|
|
345
|
+
return build_config
|
|
311
346
|
|
|
312
347
|
# To avoid unnecessary updates, only proceed if the server has actually changed
|
|
313
|
-
if
|
|
348
|
+
# OR if caching is disabled (to force refresh in non-tool mode)
|
|
349
|
+
if (_last_selected_server in (current_server_name, "")) and build_config["tool"]["show"] and use_cache:
|
|
314
350
|
if current_server_name:
|
|
315
351
|
servers_cache = safe_cache_get(self._shared_component_cache, "servers", {})
|
|
316
352
|
if isinstance(servers_cache, dict):
|
|
@@ -322,36 +358,35 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
322
358
|
return build_config
|
|
323
359
|
else:
|
|
324
360
|
return build_config
|
|
325
|
-
|
|
326
|
-
# Determine if "Tool Mode" is active by checking if the tool dropdown is hidden.
|
|
327
|
-
is_in_tool_mode = build_config["tools_metadata"]["show"]
|
|
328
361
|
safe_cache_set(self._shared_component_cache, "last_selected_server", current_server_name)
|
|
329
362
|
|
|
330
363
|
# Check if tools are already cached for this server before clearing
|
|
331
364
|
cached_tools = None
|
|
332
|
-
if current_server_name:
|
|
333
|
-
|
|
334
|
-
if
|
|
335
|
-
|
|
336
|
-
if
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
await logger.awarning(msg)
|
|
348
|
-
cached_tools = None
|
|
365
|
+
if current_server_name and use_cache:
|
|
366
|
+
servers_cache = safe_cache_get(self._shared_component_cache, "servers", {})
|
|
367
|
+
if isinstance(servers_cache, dict):
|
|
368
|
+
cached = servers_cache.get(current_server_name)
|
|
369
|
+
if cached is not None:
|
|
370
|
+
try:
|
|
371
|
+
cached_tools = cached["tools"]
|
|
372
|
+
self.tools = cached_tools
|
|
373
|
+
self.tool_names = cached["tool_names"]
|
|
374
|
+
self._tool_cache = cached["tool_cache"]
|
|
375
|
+
except (TypeError, KeyError, AttributeError) as e:
|
|
376
|
+
# Handle corrupted cache data by ignoring it
|
|
377
|
+
msg = f"Unable to use cached data for MCP Server,{current_server_name}: {e}"
|
|
378
|
+
await logger.awarning(msg)
|
|
379
|
+
cached_tools = None
|
|
349
380
|
|
|
350
381
|
# Only clear tools if we don't have cached tools for the current server
|
|
351
382
|
if not cached_tools:
|
|
352
383
|
self.tools = [] # Clear previous tools only if no cache
|
|
353
384
|
|
|
354
|
-
|
|
385
|
+
# Clear previous tool inputs if:
|
|
386
|
+
# 1. Server actually changed
|
|
387
|
+
# 2. Cache is disabled (meaning tool list will be refreshed)
|
|
388
|
+
if server_changed or not use_cache:
|
|
389
|
+
self.remove_non_default_keys(build_config)
|
|
355
390
|
|
|
356
391
|
# Only show the tool dropdown if not in tool_mode
|
|
357
392
|
if not is_in_tool_mode:
|
|
@@ -364,7 +399,12 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
364
399
|
# Show loading state only when we need to fetch tools
|
|
365
400
|
build_config["tool"]["placeholder"] = "Loading tools..."
|
|
366
401
|
build_config["tool"]["options"] = []
|
|
367
|
-
|
|
402
|
+
# Force a value refresh when:
|
|
403
|
+
# 1. Server changed
|
|
404
|
+
# 2. We don't have cached tools
|
|
405
|
+
# 3. Cache is disabled (to force refresh on config changes)
|
|
406
|
+
if server_changed or not cached_tools or not use_cache:
|
|
407
|
+
build_config["tool"]["value"] = uuid.uuid4()
|
|
368
408
|
else:
|
|
369
409
|
# Keep the tool dropdown hidden if in tool_mode
|
|
370
410
|
self._not_load_actions = True
|
|
@@ -409,18 +449,6 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
409
449
|
continue
|
|
410
450
|
return inputs
|
|
411
451
|
|
|
412
|
-
def remove_input_schema_from_build_config(
|
|
413
|
-
self, build_config: dict, tool_name: str, input_schema: dict[list[InputTypes], Any]
|
|
414
|
-
):
|
|
415
|
-
"""Remove the input schema for the tool from the build config."""
|
|
416
|
-
# Keep only schemas that don't belong to the current tool
|
|
417
|
-
input_schema = {k: v for k, v in input_schema.items() if k != tool_name}
|
|
418
|
-
# Remove all inputs from other tools
|
|
419
|
-
for value in input_schema.values():
|
|
420
|
-
for _input in value:
|
|
421
|
-
if _input.name in build_config:
|
|
422
|
-
build_config.pop(_input.name)
|
|
423
|
-
|
|
424
452
|
def remove_non_default_keys(self, build_config: dict) -> None:
|
|
425
453
|
"""Remove non-default keys from the build config."""
|
|
426
454
|
for key in list(build_config.keys()):
|
|
@@ -444,24 +472,23 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
444
472
|
return
|
|
445
473
|
|
|
446
474
|
try:
|
|
447
|
-
# Store current values before removing inputs
|
|
475
|
+
# Store current values before removing inputs (only for the current tool)
|
|
448
476
|
current_values = {}
|
|
449
477
|
for key, value in build_config.items():
|
|
450
478
|
if key not in self.default_keys and isinstance(value, dict) and "value" in value:
|
|
451
479
|
current_values[key] = value["value"]
|
|
452
480
|
|
|
453
|
-
#
|
|
454
|
-
|
|
455
|
-
self.remove_input_schema_from_build_config(build_config, tool_name, input_schema_for_all_tools)
|
|
481
|
+
# Remove ALL non-default keys (all previous tool inputs)
|
|
482
|
+
self.remove_non_default_keys(build_config)
|
|
456
483
|
|
|
457
|
-
# Get and validate new inputs
|
|
484
|
+
# Get and validate new inputs for the selected tool
|
|
458
485
|
self.schema_inputs = await self._validate_schema_inputs(tool_obj)
|
|
459
486
|
if not self.schema_inputs:
|
|
460
487
|
msg = f"No input parameters to configure for tool '{tool_name}'"
|
|
461
488
|
await logger.ainfo(msg)
|
|
462
489
|
return
|
|
463
490
|
|
|
464
|
-
# Add new inputs to build config
|
|
491
|
+
# Add new inputs to build config for the selected tool only
|
|
465
492
|
for schema_input in self.schema_inputs:
|
|
466
493
|
if not schema_input or not hasattr(schema_input, "name"):
|
|
467
494
|
msg = "Invalid schema input detected, skipping"
|
|
@@ -504,7 +531,6 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
504
531
|
if session_context:
|
|
505
532
|
self.stdio_client.set_session_context(session_context)
|
|
506
533
|
self.streamable_http_client.set_session_context(session_context)
|
|
507
|
-
|
|
508
534
|
exec_tool = self._tool_cache[self.tool]
|
|
509
535
|
tool_args = self.get_inputs_for_all_tools(self.tools)[self.tool]
|
|
510
536
|
kwargs = {}
|
|
@@ -519,11 +545,14 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
519
545
|
unflattened_kwargs = maybe_unflatten_dict(kwargs)
|
|
520
546
|
|
|
521
547
|
output = await exec_tool.coroutine(**unflattened_kwargs)
|
|
522
|
-
|
|
523
548
|
tool_content = []
|
|
524
549
|
for item in output.content:
|
|
525
550
|
item_dict = item.model_dump()
|
|
551
|
+
item_dict = self.process_output_item(item_dict)
|
|
526
552
|
tool_content.append(item_dict)
|
|
553
|
+
|
|
554
|
+
if isinstance(tool_content, list) and all(isinstance(x, dict) for x in tool_content):
|
|
555
|
+
return DataFrame(tool_content)
|
|
527
556
|
return DataFrame(data=tool_content)
|
|
528
557
|
return DataFrame(data=[{"error": "You must select a tool"}])
|
|
529
558
|
except Exception as e:
|
|
@@ -531,6 +560,16 @@ class MCPToolsComponent(ComponentWithCache):
|
|
|
531
560
|
await logger.aexception(msg)
|
|
532
561
|
raise ValueError(msg) from e
|
|
533
562
|
|
|
563
|
+
def process_output_item(self, item_dict):
|
|
564
|
+
"""Process the output of a tool."""
|
|
565
|
+
if item_dict.get("type") == "text":
|
|
566
|
+
text = item_dict.get("text")
|
|
567
|
+
try:
|
|
568
|
+
return json.loads(text)
|
|
569
|
+
except json.JSONDecodeError:
|
|
570
|
+
return item_dict
|
|
571
|
+
return item_dict
|
|
572
|
+
|
|
534
573
|
def _get_session_context(self) -> str | None:
|
|
535
574
|
"""Get the Langflow session ID for MCP session caching."""
|
|
536
575
|
# Try to get session ID from the component's execution context
|
|
@@ -16,7 +16,7 @@ from lfx.utils.constants import MESSAGE_SENDER_AI, MESSAGE_SENDER_NAME_AI, MESSA
|
|
|
16
16
|
class MemoryComponent(Component):
|
|
17
17
|
display_name = "Message History"
|
|
18
18
|
description = "Stores or retrieves stored chat messages from Langflow tables or an external memory."
|
|
19
|
-
documentation: str = "https://docs.langflow.org/
|
|
19
|
+
documentation: str = "https://docs.langflow.org/message-history"
|
|
20
20
|
icon = "message-square-more"
|
|
21
21
|
name = "Memory"
|
|
22
22
|
default_keys = ["mode", "memory", "session_id", "context_id"]
|
|
@@ -15,7 +15,7 @@ class NvidiaSystemAssistComponent(ComponentWithCache):
|
|
|
15
15
|
"The user may query GPU specifications, state, and ask the NV-API to perform "
|
|
16
16
|
"several GPU-editing acations. The prompt must be human-readable language."
|
|
17
17
|
)
|
|
18
|
-
documentation = "https://docs.langflow.org/
|
|
18
|
+
documentation = "https://docs.langflow.org/bundles-nvidia"
|
|
19
19
|
icon = "NVIDIA"
|
|
20
20
|
rise_initialized = False
|
|
21
21
|
|
lfx/components/olivya/olivya.py
CHANGED
|
@@ -11,7 +11,7 @@ from lfx.schema.data import Data
|
|
|
11
11
|
class OlivyaComponent(Component):
|
|
12
12
|
display_name = "Place Call"
|
|
13
13
|
description = "A component to create an outbound call request from Olivya's platform."
|
|
14
|
-
documentation: str = "
|
|
14
|
+
documentation: str = "https://docs.olivya.io"
|
|
15
15
|
icon = "Olivya"
|
|
16
16
|
name = "OlivyaComponent"
|
|
17
17
|
|