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.
Files changed (237) hide show
  1. lfx/_assets/component_index.json +1 -1
  2. lfx/base/agents/agent.py +121 -29
  3. lfx/base/agents/altk_base_agent.py +380 -0
  4. lfx/base/agents/altk_tool_wrappers.py +565 -0
  5. lfx/base/agents/events.py +103 -35
  6. lfx/base/agents/utils.py +15 -2
  7. lfx/base/composio/composio_base.py +183 -233
  8. lfx/base/data/base_file.py +88 -21
  9. lfx/base/data/storage_utils.py +192 -0
  10. lfx/base/data/utils.py +178 -14
  11. lfx/base/datastax/__init__.py +5 -0
  12. lfx/{components/vectorstores/astradb.py → base/datastax/astradb_base.py} +84 -473
  13. lfx/base/embeddings/embeddings_class.py +113 -0
  14. lfx/base/io/chat.py +5 -4
  15. lfx/base/mcp/util.py +101 -15
  16. lfx/base/models/groq_constants.py +74 -58
  17. lfx/base/models/groq_model_discovery.py +265 -0
  18. lfx/base/models/model.py +1 -1
  19. lfx/base/models/model_input_constants.py +74 -7
  20. lfx/base/models/model_utils.py +100 -0
  21. lfx/base/models/ollama_constants.py +3 -0
  22. lfx/base/models/openai_constants.py +7 -0
  23. lfx/base/models/watsonx_constants.py +36 -0
  24. lfx/base/tools/run_flow.py +601 -129
  25. lfx/cli/commands.py +7 -4
  26. lfx/cli/common.py +2 -2
  27. lfx/cli/run.py +1 -1
  28. lfx/cli/script_loader.py +53 -11
  29. lfx/components/Notion/create_page.py +1 -1
  30. lfx/components/Notion/list_database_properties.py +1 -1
  31. lfx/components/Notion/list_pages.py +1 -1
  32. lfx/components/Notion/list_users.py +1 -1
  33. lfx/components/Notion/page_content_viewer.py +1 -1
  34. lfx/components/Notion/search.py +1 -1
  35. lfx/components/Notion/update_page_property.py +1 -1
  36. lfx/components/__init__.py +19 -5
  37. lfx/components/altk/__init__.py +34 -0
  38. lfx/components/altk/altk_agent.py +193 -0
  39. lfx/components/amazon/amazon_bedrock_converse.py +1 -1
  40. lfx/components/apify/apify_actor.py +4 -4
  41. lfx/components/composio/__init__.py +70 -18
  42. lfx/components/composio/apollo_composio.py +11 -0
  43. lfx/components/composio/bitbucket_composio.py +11 -0
  44. lfx/components/composio/canva_composio.py +11 -0
  45. lfx/components/composio/coda_composio.py +11 -0
  46. lfx/components/composio/composio_api.py +10 -0
  47. lfx/components/composio/discord_composio.py +1 -1
  48. lfx/components/composio/elevenlabs_composio.py +11 -0
  49. lfx/components/composio/exa_composio.py +11 -0
  50. lfx/components/composio/firecrawl_composio.py +11 -0
  51. lfx/components/composio/fireflies_composio.py +11 -0
  52. lfx/components/composio/gmail_composio.py +1 -1
  53. lfx/components/composio/googlebigquery_composio.py +11 -0
  54. lfx/components/composio/googlecalendar_composio.py +1 -1
  55. lfx/components/composio/googledocs_composio.py +1 -1
  56. lfx/components/composio/googlemeet_composio.py +1 -1
  57. lfx/components/composio/googlesheets_composio.py +1 -1
  58. lfx/components/composio/googletasks_composio.py +1 -1
  59. lfx/components/composio/heygen_composio.py +11 -0
  60. lfx/components/composio/mem0_composio.py +11 -0
  61. lfx/components/composio/peopledatalabs_composio.py +11 -0
  62. lfx/components/composio/perplexityai_composio.py +11 -0
  63. lfx/components/composio/serpapi_composio.py +11 -0
  64. lfx/components/composio/slack_composio.py +3 -574
  65. lfx/components/composio/slackbot_composio.py +1 -1
  66. lfx/components/composio/snowflake_composio.py +11 -0
  67. lfx/components/composio/tavily_composio.py +11 -0
  68. lfx/components/composio/youtube_composio.py +2 -2
  69. lfx/components/{agents → cuga}/__init__.py +5 -7
  70. lfx/components/cuga/cuga_agent.py +730 -0
  71. lfx/components/data/__init__.py +78 -28
  72. lfx/components/data_source/__init__.py +58 -0
  73. lfx/components/{data → data_source}/api_request.py +26 -3
  74. lfx/components/{data → data_source}/csv_to_data.py +15 -10
  75. lfx/components/{data → data_source}/json_to_data.py +15 -8
  76. lfx/components/{data → data_source}/news_search.py +1 -1
  77. lfx/components/{data → data_source}/rss.py +1 -1
  78. lfx/components/{data → data_source}/sql_executor.py +1 -1
  79. lfx/components/{data → data_source}/url.py +1 -1
  80. lfx/components/{data → data_source}/web_search.py +1 -1
  81. lfx/components/datastax/__init__.py +12 -6
  82. lfx/components/datastax/{astra_assistant_manager.py → astradb_assistant_manager.py} +1 -0
  83. lfx/components/datastax/astradb_chatmemory.py +40 -0
  84. lfx/components/datastax/astradb_cql.py +6 -32
  85. lfx/components/datastax/astradb_graph.py +10 -124
  86. lfx/components/datastax/astradb_tool.py +13 -53
  87. lfx/components/datastax/astradb_vectorstore.py +134 -977
  88. lfx/components/datastax/create_assistant.py +1 -0
  89. lfx/components/datastax/create_thread.py +1 -0
  90. lfx/components/datastax/dotenv.py +1 -0
  91. lfx/components/datastax/get_assistant.py +1 -0
  92. lfx/components/datastax/getenvvar.py +1 -0
  93. lfx/components/datastax/graph_rag.py +1 -1
  94. lfx/components/datastax/hcd.py +1 -1
  95. lfx/components/datastax/list_assistants.py +1 -0
  96. lfx/components/datastax/run.py +1 -0
  97. lfx/components/deactivated/json_document_builder.py +1 -1
  98. lfx/components/elastic/elasticsearch.py +1 -1
  99. lfx/components/elastic/opensearch_multimodal.py +1575 -0
  100. lfx/components/files_and_knowledge/__init__.py +47 -0
  101. lfx/components/{data → files_and_knowledge}/directory.py +1 -1
  102. lfx/components/{data → files_and_knowledge}/file.py +246 -18
  103. lfx/components/{knowledge_bases → files_and_knowledge}/ingestion.py +17 -9
  104. lfx/components/{knowledge_bases → files_and_knowledge}/retrieval.py +18 -10
  105. lfx/components/{data → files_and_knowledge}/save_file.py +142 -22
  106. lfx/components/flow_controls/__init__.py +58 -0
  107. lfx/components/{logic → flow_controls}/conditional_router.py +1 -1
  108. lfx/components/{logic → flow_controls}/loop.py +47 -9
  109. lfx/components/flow_controls/run_flow.py +108 -0
  110. lfx/components/glean/glean_search_api.py +1 -1
  111. lfx/components/groq/groq.py +35 -28
  112. lfx/components/helpers/__init__.py +102 -0
  113. lfx/components/ibm/watsonx.py +25 -21
  114. lfx/components/input_output/__init__.py +3 -1
  115. lfx/components/input_output/chat.py +12 -3
  116. lfx/components/input_output/chat_output.py +12 -4
  117. lfx/components/input_output/text.py +1 -1
  118. lfx/components/input_output/text_output.py +1 -1
  119. lfx/components/{data → input_output}/webhook.py +1 -1
  120. lfx/components/knowledge_bases/__init__.py +59 -4
  121. lfx/components/langchain_utilities/character.py +1 -1
  122. lfx/components/langchain_utilities/csv_agent.py +84 -16
  123. lfx/components/langchain_utilities/json_agent.py +67 -12
  124. lfx/components/langchain_utilities/language_recursive.py +1 -1
  125. lfx/components/llm_operations/__init__.py +46 -0
  126. lfx/components/{processing → llm_operations}/batch_run.py +1 -1
  127. lfx/components/{processing → llm_operations}/lambda_filter.py +1 -1
  128. lfx/components/{logic → llm_operations}/llm_conditional_router.py +1 -1
  129. lfx/components/{processing/llm_router.py → llm_operations/llm_selector.py} +3 -3
  130. lfx/components/{processing → llm_operations}/structured_output.py +56 -18
  131. lfx/components/logic/__init__.py +126 -0
  132. lfx/components/mem0/mem0_chat_memory.py +11 -0
  133. lfx/components/mistral/mistral_embeddings.py +1 -1
  134. lfx/components/models/__init__.py +64 -9
  135. lfx/components/models_and_agents/__init__.py +49 -0
  136. lfx/components/{agents → models_and_agents}/agent.py +49 -6
  137. lfx/components/models_and_agents/embedding_model.py +423 -0
  138. lfx/components/models_and_agents/language_model.py +398 -0
  139. lfx/components/{agents → models_and_agents}/mcp_component.py +84 -45
  140. lfx/components/{helpers → models_and_agents}/memory.py +1 -1
  141. lfx/components/nvidia/system_assist.py +1 -1
  142. lfx/components/olivya/olivya.py +1 -1
  143. lfx/components/ollama/ollama.py +235 -14
  144. lfx/components/openrouter/openrouter.py +49 -147
  145. lfx/components/processing/__init__.py +9 -57
  146. lfx/components/processing/converter.py +1 -1
  147. lfx/components/processing/dataframe_operations.py +1 -1
  148. lfx/components/processing/parse_json_data.py +2 -2
  149. lfx/components/processing/parser.py +7 -2
  150. lfx/components/processing/split_text.py +1 -1
  151. lfx/components/qdrant/qdrant.py +1 -1
  152. lfx/components/redis/redis.py +1 -1
  153. lfx/components/twelvelabs/split_video.py +10 -0
  154. lfx/components/twelvelabs/video_file.py +12 -0
  155. lfx/components/utilities/__init__.py +43 -0
  156. lfx/components/{helpers → utilities}/calculator_core.py +1 -1
  157. lfx/components/{helpers → utilities}/current_date.py +1 -1
  158. lfx/components/{processing → utilities}/python_repl_core.py +1 -1
  159. lfx/components/vectorstores/__init__.py +0 -6
  160. lfx/components/vectorstores/local_db.py +9 -0
  161. lfx/components/youtube/youtube_transcripts.py +118 -30
  162. lfx/custom/custom_component/component.py +60 -3
  163. lfx/custom/custom_component/custom_component.py +68 -6
  164. lfx/field_typing/constants.py +1 -0
  165. lfx/graph/edge/base.py +45 -22
  166. lfx/graph/graph/base.py +5 -2
  167. lfx/graph/graph/schema.py +3 -2
  168. lfx/graph/state/model.py +15 -2
  169. lfx/graph/utils.py +6 -0
  170. lfx/graph/vertex/base.py +4 -1
  171. lfx/graph/vertex/param_handler.py +10 -7
  172. lfx/graph/vertex/vertex_types.py +1 -1
  173. lfx/helpers/__init__.py +12 -0
  174. lfx/helpers/flow.py +117 -0
  175. lfx/inputs/input_mixin.py +24 -1
  176. lfx/inputs/inputs.py +13 -1
  177. lfx/interface/components.py +161 -83
  178. lfx/io/schema.py +6 -0
  179. lfx/log/logger.py +5 -3
  180. lfx/schema/schema.py +5 -0
  181. lfx/services/database/__init__.py +5 -0
  182. lfx/services/database/service.py +25 -0
  183. lfx/services/deps.py +87 -22
  184. lfx/services/manager.py +19 -6
  185. lfx/services/mcp_composer/service.py +998 -157
  186. lfx/services/session.py +5 -0
  187. lfx/services/settings/base.py +51 -7
  188. lfx/services/settings/constants.py +8 -0
  189. lfx/services/storage/local.py +76 -46
  190. lfx/services/storage/service.py +152 -29
  191. lfx/template/field/base.py +3 -0
  192. lfx/utils/ssrf_protection.py +384 -0
  193. lfx/utils/validate_cloud.py +26 -0
  194. {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/METADATA +38 -22
  195. {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/RECORD +210 -196
  196. {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/WHEEL +1 -1
  197. lfx/components/agents/cuga_agent.py +0 -1013
  198. lfx/components/datastax/astra_db.py +0 -77
  199. lfx/components/datastax/cassandra.py +0 -92
  200. lfx/components/logic/run_flow.py +0 -71
  201. lfx/components/models/embedding_model.py +0 -114
  202. lfx/components/models/language_model.py +0 -144
  203. lfx/components/vectorstores/astradb_graph.py +0 -326
  204. lfx/components/vectorstores/cassandra.py +0 -264
  205. lfx/components/vectorstores/cassandra_graph.py +0 -238
  206. lfx/components/vectorstores/chroma.py +0 -167
  207. lfx/components/vectorstores/clickhouse.py +0 -135
  208. lfx/components/vectorstores/couchbase.py +0 -102
  209. lfx/components/vectorstores/elasticsearch.py +0 -267
  210. lfx/components/vectorstores/faiss.py +0 -111
  211. lfx/components/vectorstores/graph_rag.py +0 -141
  212. lfx/components/vectorstores/hcd.py +0 -314
  213. lfx/components/vectorstores/milvus.py +0 -115
  214. lfx/components/vectorstores/mongodb_atlas.py +0 -213
  215. lfx/components/vectorstores/opensearch.py +0 -243
  216. lfx/components/vectorstores/pgvector.py +0 -72
  217. lfx/components/vectorstores/pinecone.py +0 -134
  218. lfx/components/vectorstores/qdrant.py +0 -109
  219. lfx/components/vectorstores/supabase.py +0 -76
  220. lfx/components/vectorstores/upstash.py +0 -124
  221. lfx/components/vectorstores/vectara.py +0 -97
  222. lfx/components/vectorstores/vectara_rag.py +0 -164
  223. lfx/components/vectorstores/weaviate.py +0 -89
  224. /lfx/components/{data → data_source}/mock_data.py +0 -0
  225. /lfx/components/datastax/{astra_vectorize.py → astradb_vectorize.py} +0 -0
  226. /lfx/components/{logic → flow_controls}/data_conditional_router.py +0 -0
  227. /lfx/components/{logic → flow_controls}/flow_tool.py +0 -0
  228. /lfx/components/{logic → flow_controls}/listen.py +0 -0
  229. /lfx/components/{logic → flow_controls}/notify.py +0 -0
  230. /lfx/components/{logic → flow_controls}/pass_message.py +0 -0
  231. /lfx/components/{logic → flow_controls}/sub_flow.py +0 -0
  232. /lfx/components/{processing → models_and_agents}/prompt.py +0 -0
  233. /lfx/components/{helpers → processing}/create_list.py +0 -0
  234. /lfx/components/{helpers → processing}/output_parser.py +0 -0
  235. /lfx/components/{helpers → processing}/store_message.py +0 -0
  236. /lfx/components/{helpers → utilities}/id_generator.py +0 -0
  237. {lfx_nightly-0.1.13.dev0.dist-info → lfx_nightly-0.2.0.dev26.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,7 @@
1
- import requests
2
1
  from pydantic.v1 import SecretStr
3
2
 
4
- from lfx.base.models.groq_constants import GROQ_MODELS, TOOL_CALLING_UNSUPPORTED_GROQ_MODELS, UNSUPPORTED_GROQ_MODELS
3
+ from lfx.base.models.groq_constants import GROQ_MODELS
4
+ from lfx.base.models.groq_model_discovery import get_groq_models
5
5
  from lfx.base.models.model import LCModelComponent
6
6
  from lfx.field_typing import LanguageModel
7
7
  from lfx.field_typing.range_spec import RangeSpec
@@ -52,7 +52,7 @@ class GroqModel(LCModelComponent):
52
52
  DropdownInput(
53
53
  name="model_name",
54
54
  display_name="Model",
55
- info="The name of the model to use.",
55
+ info="The name of the model to use. Add your Groq API key to access additional available models.",
56
56
  options=GROQ_MODELS,
57
57
  value=GROQ_MODELS[0],
58
58
  refresh_button=True,
@@ -71,35 +71,42 @@ class GroqModel(LCModelComponent):
71
71
  ]
72
72
 
73
73
  def get_models(self, *, tool_model_enabled: bool | None = None) -> list[str]:
74
+ """Get available Groq models using the dynamic discovery system.
75
+
76
+ This method uses the groq_model_discovery module which:
77
+ - Fetches models directly from Groq API
78
+ - Automatically tests tool calling support
79
+ - Caches results for 24 hours
80
+ - Falls back to hardcoded list if API fails
81
+
82
+ Args:
83
+ tool_model_enabled: If True, only return models that support tool calling
84
+
85
+ Returns:
86
+ List of available model IDs
87
+ """
74
88
  try:
75
- url = f"{self.base_url}/openai/v1/models"
76
- headers = {"Authorization": f"Bearer {self.api_key}", "Content-Type": "application/json"}
89
+ # Get models with metadata from dynamic discovery system
90
+ api_key = self.api_key if hasattr(self, "api_key") and self.api_key else None
91
+ models_metadata = get_groq_models(api_key=api_key)
77
92
 
78
- response = requests.get(url, headers=headers, timeout=10)
79
- response.raise_for_status()
80
- model_list = response.json()
93
+ # Filter out non-LLM models (audio, TTS, guards)
81
94
  model_ids = [
82
- model["id"] for model in model_list.get("data", []) if model["id"] not in UNSUPPORTED_GROQ_MODELS
95
+ model_id for model_id, metadata in models_metadata.items() if not metadata.get("not_supported", False)
83
96
  ]
84
- except (ImportError, ValueError, requests.exceptions.RequestException) as e:
97
+
98
+ # Filter by tool calling support if requested
99
+ if tool_model_enabled:
100
+ model_ids = [model_id for model_id in model_ids if models_metadata[model_id].get("tool_calling", False)]
101
+ logger.info(f"Loaded {len(model_ids)} Groq models with tool calling support")
102
+ else:
103
+ logger.info(f"Loaded {len(model_ids)} Groq models")
104
+ except (ValueError, KeyError, TypeError, ImportError) as e:
85
105
  logger.exception(f"Error getting model names: {e}")
86
- model_ids = GROQ_MODELS
87
- if tool_model_enabled:
88
- try:
89
- from langchain_groq import ChatGroq
90
- except ImportError as e:
91
- msg = "langchain_groq is not installed. Please install it with `pip install langchain_groq`."
92
- raise ImportError(msg) from e
93
- for model in model_ids:
94
- model_with_tool = ChatGroq(
95
- model=model,
96
- api_key=self.api_key,
97
- base_url=self.base_url,
98
- )
99
- if not self.supports_tool_calling(model_with_tool) or model in TOOL_CALLING_UNSUPPORTED_GROQ_MODELS:
100
- model_ids.remove(model)
106
+ # Fallback to hardcoded list from groq_constants.py
107
+ return GROQ_MODELS
108
+ else:
101
109
  return model_ids
102
- return model_ids
103
110
 
104
111
  def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None):
105
112
  if field_name in {"base_url", "model_name", "tool_model_enabled", "api_key"} and field_value:
@@ -107,13 +114,13 @@ class GroqModel(LCModelComponent):
107
114
  if len(self.api_key) != 0:
108
115
  try:
109
116
  ids = self.get_models(tool_model_enabled=self.tool_model_enabled)
110
- except (ImportError, ValueError, requests.exceptions.RequestException) as e:
117
+ except (ValueError, KeyError, TypeError, ImportError) as e:
111
118
  logger.exception(f"Error getting model names: {e}")
112
119
  ids = GROQ_MODELS
113
120
  build_config.setdefault("model_name", {})
114
121
  build_config["model_name"]["options"] = ids
115
122
  build_config["model_name"].setdefault("value", ids[0])
116
- except Exception as e:
123
+ except (ValueError, KeyError, TypeError, AttributeError) as e:
117
124
  msg = f"Error getting model names: {e}"
118
125
  raise ValueError(msg) from e
119
126
  return build_config
@@ -1,5 +1,8 @@
1
+ """Helpers module - backwards compatibility for moved components."""
2
+
1
3
  from __future__ import annotations
2
4
 
5
+ import sys
3
6
  from typing import TYPE_CHECKING, Any
4
7
 
5
8
  from lfx.components._importing import import_mod
@@ -33,12 +36,111 @@ __all__ = [
33
36
  "OutputParserComponent",
34
37
  ]
35
38
 
39
+ # Register redirected submodules in sys.modules for direct importlib.import_module() calls
40
+ # This allows imports like: import lfx.components.helpers.current_date
41
+ _redirected_submodules = {
42
+ "lfx.components.helpers.current_date": "lfx.components.utilities.current_date",
43
+ "lfx.components.helpers.calculator_core": "lfx.components.utilities.calculator_core",
44
+ "lfx.components.helpers.id_generator": "lfx.components.utilities.id_generator",
45
+ "lfx.components.helpers.memory": "lfx.components.models_and_agents.memory",
46
+ }
47
+
48
+ for old_path, new_path in _redirected_submodules.items():
49
+ if old_path not in sys.modules:
50
+ # Use a lazy loader that imports the actual module when accessed
51
+ class _RedirectedModule:
52
+ def __init__(self, target_path: str, original_path: str):
53
+ self._target_path = target_path
54
+ self._original_path = original_path
55
+ self._module = None
56
+
57
+ def __getattr__(self, name: str) -> Any:
58
+ if self._module is None:
59
+ from importlib import import_module
60
+
61
+ self._module = import_module(self._target_path)
62
+ # Also register under the original path for future imports
63
+ sys.modules[self._original_path] = self._module
64
+ return getattr(self._module, name)
65
+
66
+ def __repr__(self) -> str:
67
+ return f"<redirected module '{self._original_path}' -> '{self._target_path}'>"
68
+
69
+ sys.modules[old_path] = _RedirectedModule(new_path, old_path)
70
+
36
71
 
37
72
  def __getattr__(attr_name: str) -> Any:
38
73
  """Lazily import helper components on attribute access."""
74
+ # Handle submodule access for backwards compatibility
75
+ # e.g., lfx.components.helpers.id_generator -> lfx.components.utilities.id_generator
76
+ if attr_name == "id_generator":
77
+ from importlib import import_module
78
+
79
+ result = import_module("lfx.components.utilities.id_generator")
80
+ globals()[attr_name] = result
81
+ return result
82
+ if attr_name == "calculator_core":
83
+ from importlib import import_module
84
+
85
+ result = import_module("lfx.components.utilities.calculator_core")
86
+ globals()[attr_name] = result
87
+ return result
88
+ if attr_name == "current_date":
89
+ from importlib import import_module
90
+
91
+ result = import_module("lfx.components.utilities.current_date")
92
+ globals()[attr_name] = result
93
+ return result
94
+ if attr_name == "memory":
95
+ from importlib import import_module
96
+
97
+ result = import_module("lfx.components.models_and_agents.memory")
98
+ globals()[attr_name] = result
99
+ return result
100
+
39
101
  if attr_name not in _dynamic_imports:
40
102
  msg = f"module '{__name__}' has no attribute '{attr_name}'"
41
103
  raise AttributeError(msg)
104
+
105
+ # CurrentDateComponent, CalculatorComponent, and IDGeneratorComponent were moved to utilities
106
+ # Forward them to utilities for backwards compatibility
107
+ if attr_name in ("CurrentDateComponent", "CalculatorComponent", "IDGeneratorComponent"):
108
+ from lfx.components import utilities
109
+
110
+ result = getattr(utilities, attr_name)
111
+ globals()[attr_name] = result
112
+ return result
113
+
114
+ # MemoryComponent was moved to models_and_agents
115
+ # Forward it to models_and_agents for backwards compatibility
116
+ if attr_name == "MemoryComponent":
117
+ from lfx.components import models_and_agents
118
+
119
+ result = getattr(models_and_agents, attr_name)
120
+ globals()[attr_name] = result
121
+ return result
122
+
123
+ # CreateListComponent, MessageStoreComponent, and OutputParserComponent were moved to processing
124
+ # Forward them to processing for backwards compatibility
125
+ if attr_name == "CreateListComponent":
126
+ from lfx.components import processing
127
+
128
+ result = getattr(processing, attr_name)
129
+ globals()[attr_name] = result
130
+ return result
131
+ if attr_name == "MessageStoreComponent":
132
+ from lfx.components import processing
133
+
134
+ result = processing.MessageStoreComponent
135
+ globals()[attr_name] = result
136
+ return result
137
+ if attr_name == "OutputParserComponent":
138
+ from lfx.components import processing
139
+
140
+ result = getattr(processing, attr_name)
141
+ globals()[attr_name] = result
142
+ return result
143
+
42
144
  try:
43
145
  result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
44
146
  except (ModuleNotFoundError, ImportError, AttributeError) as e:
@@ -21,23 +21,24 @@ class WatsonxAIComponent(LCModelComponent):
21
21
  beta = False
22
22
 
23
23
  _default_models = ["ibm/granite-3-2b-instruct", "ibm/granite-3-8b-instruct", "ibm/granite-13b-instruct-v2"]
24
-
24
+ _urls = [
25
+ "https://us-south.ml.cloud.ibm.com",
26
+ "https://eu-de.ml.cloud.ibm.com",
27
+ "https://eu-gb.ml.cloud.ibm.com",
28
+ "https://au-syd.ml.cloud.ibm.com",
29
+ "https://jp-tok.ml.cloud.ibm.com",
30
+ "https://ca-tor.ml.cloud.ibm.com",
31
+ ]
25
32
  inputs = [
26
33
  *LCModelComponent.get_base_inputs(),
27
34
  DropdownInput(
28
- name="url",
35
+ name="base_url",
29
36
  display_name="watsonx API Endpoint",
30
37
  info="The base URL of the API.",
31
- value=None,
32
- options=[
33
- "https://us-south.ml.cloud.ibm.com",
34
- "https://eu-de.ml.cloud.ibm.com",
35
- "https://eu-gb.ml.cloud.ibm.com",
36
- "https://au-syd.ml.cloud.ibm.com",
37
- "https://jp-tok.ml.cloud.ibm.com",
38
- "https://ca-tor.ml.cloud.ibm.com",
39
- ],
38
+ value=[],
39
+ options=_urls,
40
40
  real_time_refresh=True,
41
+ required=True,
41
42
  ),
42
43
  StrInput(
43
44
  name="project_id",
@@ -56,8 +57,9 @@ class WatsonxAIComponent(LCModelComponent):
56
57
  display_name="Model Name",
57
58
  options=[],
58
59
  value=None,
59
- dynamic=True,
60
+ real_time_refresh=True,
60
61
  required=True,
62
+ refresh_button=True,
61
63
  ),
62
64
  IntInput(
63
65
  name="max_tokens",
@@ -155,18 +157,20 @@ class WatsonxAIComponent(LCModelComponent):
155
157
 
156
158
  def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
157
159
  """Update model options when URL or API key changes."""
158
- logger.info("Updating build config. Field name: %s, Field value: %s", field_name, field_value)
159
-
160
- if field_name == "url" and field_value:
160
+ if field_name == "base_url" and field_value:
161
161
  try:
162
- models = self.fetch_models(base_url=build_config.url.value)
163
- build_config.model_name.options = models
164
- if build_config.model_name.value:
165
- build_config.model_name.value = models[0]
166
- info_message = f"Updated model options: {len(models)} models found in {build_config.url.value}"
162
+ models = self.fetch_models(base_url=field_value)
163
+ build_config["model_name"]["options"] = models
164
+ if build_config["model_name"]["value"]:
165
+ build_config["model_name"]["value"] = models[0]
166
+ info_message = f"Updated model options: {len(models)} models found in {field_value}"
167
167
  logger.info(info_message)
168
168
  except Exception: # noqa: BLE001
169
169
  logger.exception("Error updating model options.")
170
+ if field_name == "model_name" and field_value and field_value in WatsonxAIComponent._urls:
171
+ build_config["model_name"]["options"] = self.fetch_models(base_url=field_value)
172
+ build_config["model_name"]["value"] = ""
173
+ return build_config
170
174
 
171
175
  def build_model(self) -> LanguageModel:
172
176
  # Parse logit_bias from JSON string if provided
@@ -195,7 +199,7 @@ class WatsonxAIComponent(LCModelComponent):
195
199
 
196
200
  return ChatWatsonx(
197
201
  apikey=SecretStr(self.api_key).get_secret_value(),
198
- url=self.url,
202
+ url=self.base_url,
199
203
  project_id=self.project_id,
200
204
  model_id=self.model_name,
201
205
  params=chat_params,
@@ -9,15 +9,17 @@ if TYPE_CHECKING:
9
9
  from lfx.components.input_output.chat_output import ChatOutput
10
10
  from lfx.components.input_output.text import TextInputComponent
11
11
  from lfx.components.input_output.text_output import TextOutputComponent
12
+ from lfx.components.input_output.webhook import WebhookComponent
12
13
 
13
14
  _dynamic_imports = {
14
15
  "ChatInput": "chat",
15
16
  "ChatOutput": "chat_output",
16
17
  "TextInputComponent": "text",
17
18
  "TextOutputComponent": "text_output",
19
+ "WebhookComponent": "webhook",
18
20
  }
19
21
 
20
- __all__ = ["ChatInput", "ChatOutput", "TextInputComponent", "TextOutputComponent"]
22
+ __all__ = ["ChatInput", "ChatOutput", "TextInputComponent", "TextOutputComponent", "WebhookComponent"]
21
23
 
22
24
 
23
25
  def __getattr__(attr_name: str) -> Any:
@@ -19,7 +19,7 @@ from lfx.utils.constants import (
19
19
  class ChatInput(ChatComponent):
20
20
  display_name = "Chat Input"
21
21
  description = "Get chat inputs from the Playground."
22
- documentation: str = "https://docs.langflow.org/components-io#chat-input"
22
+ documentation: str = "https://docs.langflow.org/chat-input-and-output"
23
23
  icon = "MessagesSquare"
24
24
  name = "ChatInput"
25
25
  minimized = True
@@ -60,6 +60,13 @@ class ChatInput(ChatComponent):
60
60
  info="The session ID of the chat. If empty, the current session ID parameter will be used.",
61
61
  advanced=True,
62
62
  ),
63
+ MessageTextInput(
64
+ name="context_id",
65
+ display_name="Context ID",
66
+ info="The context ID of the chat. Adds an extra layer to the local memory.",
67
+ value="",
68
+ advanced=True,
69
+ ),
63
70
  FileInput(
64
71
  name="files",
65
72
  display_name="Files",
@@ -82,14 +89,16 @@ class ChatInput(ChatComponent):
82
89
  # Filter out None/empty values
83
90
  files = [f for f in files if f is not None and f != ""]
84
91
 
92
+ session_id = self.session_id or self.graph.session_id or ""
85
93
  message = await Message.create(
86
94
  text=self.input_value,
87
95
  sender=self.sender,
88
96
  sender_name=self.sender_name,
89
- session_id=self.session_id,
97
+ session_id=session_id,
98
+ context_id=self.context_id,
90
99
  files=files,
91
100
  )
92
- if self.session_id and isinstance(message, Message) and self.should_store_message:
101
+ if session_id and isinstance(message, Message) and self.should_store_message:
93
102
  stored_message = await self.send_message(
94
103
  message,
95
104
  )
@@ -22,7 +22,7 @@ from lfx.utils.constants import (
22
22
  class ChatOutput(ChatComponent):
23
23
  display_name = "Chat Output"
24
24
  description = "Display a chat message in the Playground."
25
- documentation: str = "https://docs.langflow.org/components-io#chat-output"
25
+ documentation: str = "https://docs.langflow.org/chat-input-and-output"
26
26
  icon = "MessagesSquare"
27
27
  name = "ChatOutput"
28
28
  minimized = True
@@ -63,6 +63,13 @@ class ChatOutput(ChatComponent):
63
63
  info="The session ID of the chat. If empty, the current session ID parameter will be used.",
64
64
  advanced=True,
65
65
  ),
66
+ MessageTextInput(
67
+ name="context_id",
68
+ display_name="Context ID",
69
+ info="The context ID of the chat. Adds an extra layer to the local memory.",
70
+ value="",
71
+ advanced=True,
72
+ ),
66
73
  MessageTextInput(
67
74
  name="data_template",
68
75
  display_name="Data Template",
@@ -110,7 +117,7 @@ class ChatOutput(ChatComponent):
110
117
  source, _, display_name, source_id = self.get_properties_from_source_component()
111
118
 
112
119
  # Create or use existing Message object
113
- if isinstance(self.input_value, Message):
120
+ if isinstance(self.input_value, Message) and not self.is_connected_to_chat_input():
114
121
  message = self.input_value
115
122
  # Update message properties
116
123
  message.text = text
@@ -120,12 +127,13 @@ class ChatOutput(ChatComponent):
120
127
  # Set message properties
121
128
  message.sender = self.sender
122
129
  message.sender_name = self.sender_name
123
- message.session_id = self.session_id
130
+ message.session_id = self.session_id or self.graph.session_id or ""
131
+ message.context_id = self.context_id
124
132
  message.flow_id = self.graph.flow_id if hasattr(self, "graph") else None
125
133
  message.properties.source = self._build_source(source_id, display_name, source)
126
134
 
127
135
  # Store message if needed
128
- if self.session_id and self.should_store_message:
136
+ if message.session_id and self.should_store_message:
129
137
  stored_message = await self.send_message(message)
130
138
  self.message.value = stored_message
131
139
  message = stored_message
@@ -6,7 +6,7 @@ from lfx.schema.message import Message
6
6
  class TextInputComponent(TextComponent):
7
7
  display_name = "Text Input"
8
8
  description = "Get user text inputs."
9
- documentation: str = "https://docs.langflow.org/components-io#text-input"
9
+ documentation: str = "https://docs.langflow.org/text-input-and-output"
10
10
  icon = "type"
11
11
  name = "TextInput"
12
12
 
@@ -6,7 +6,7 @@ from lfx.schema.message import Message
6
6
  class TextOutputComponent(TextComponent):
7
7
  display_name = "Text Output"
8
8
  description = "Sends text output via API."
9
- documentation: str = "https://docs.langflow.org/components-io#text-output"
9
+ documentation: str = "https://docs.langflow.org/text-input-and-output"
10
10
  icon = "type"
11
11
  name = "TextOutput"
12
12
 
@@ -7,7 +7,7 @@ from lfx.schema.data import Data
7
7
 
8
8
  class WebhookComponent(Component):
9
9
  display_name = "Webhook"
10
- documentation: str = "https://docs.langflow.org/components-data#webhook"
10
+ documentation: str = "https://docs.langflow.org/component-webhook"
11
11
  name = "Webhook"
12
12
  icon = "webhook"
13
13
 
@@ -1,12 +1,19 @@
1
+ """Knowledge bases module - backwards compatibility alias for files_and_knowledge.
2
+
3
+ This module provides backwards compatibility by forwarding all imports
4
+ to files_and_knowledge where the actual knowledge base 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
6
13
 
7
14
  if TYPE_CHECKING:
8
- from lfx.components.knowledge_bases.ingestion import KnowledgeIngestionComponent
9
- from lfx.components.knowledge_bases.retrieval import KnowledgeRetrievalComponent
15
+ from lfx.components.files_and_knowledge.ingestion import KnowledgeIngestionComponent
16
+ from lfx.components.files_and_knowledge.retrieval import KnowledgeRetrievalComponent
10
17
 
11
18
  _dynamic_imports = {
12
19
  "KnowledgeIngestionComponent": "ingestion",
@@ -15,14 +22,61 @@ _dynamic_imports = {
15
22
 
16
23
  __all__ = ["KnowledgeIngestionComponent", "KnowledgeRetrievalComponent"]
17
24
 
25
+ # Register redirected submodules in sys.modules for direct importlib.import_module() calls
26
+ # This allows imports like: import lfx.components.knowledge_bases.ingestion
27
+ _redirected_submodules = {
28
+ "lfx.components.knowledge_bases.ingestion": "lfx.components.files_and_knowledge.ingestion",
29
+ "lfx.components.knowledge_bases.retrieval": "lfx.components.files_and_knowledge.retrieval",
30
+ }
31
+
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)
54
+
18
55
 
19
56
  def __getattr__(attr_name: str) -> Any:
20
- """Lazily import input/output components on attribute access."""
57
+ """Forward attribute access to files_and_knowledge components."""
58
+ # Handle submodule access for backwards compatibility
59
+ if attr_name == "ingestion":
60
+ from importlib import import_module
61
+
62
+ result = import_module("lfx.components.files_and_knowledge.ingestion")
63
+ globals()[attr_name] = result
64
+ return result
65
+ if attr_name == "retrieval":
66
+ from importlib import import_module
67
+
68
+ result = import_module("lfx.components.files_and_knowledge.retrieval")
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 files_and_knowledge using the correct package path
77
+ package = "lfx.components.files_and_knowledge"
24
78
  try:
25
- result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
79
+ result = import_mod(attr_name, _dynamic_imports[attr_name], package)
26
80
  except (ModuleNotFoundError, ImportError, AttributeError) as e:
27
81
  msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
28
82
  raise AttributeError(msg) from e
@@ -31,4 +85,5 @@ def __getattr__(attr_name: str) -> Any:
31
85
 
32
86
 
33
87
  def __dir__() -> list[str]:
88
+ """Return directory of available components."""
34
89
  return list(__all__)
@@ -10,7 +10,7 @@ from lfx.utils.util import unescape_string
10
10
  class CharacterTextSplitterComponent(LCTextSplitterComponent):
11
11
  display_name = "Character Text Splitter"
12
12
  description = "Split text by number of characters."
13
- documentation = "https://docs.langflow.org/components/text-splitters#charactertextsplitter"
13
+ documentation = "https://docs.langflow.org/bundles-langchain"
14
14
  name = "CharacterTextSplitter"
15
15
  icon = "LangChain"
16
16