lfx-nightly 0.2.0.dev25__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.

Potentially problematic release.


This version of lfx-nightly might be problematic. Click here for more details.

Files changed (769) hide show
  1. lfx/__init__.py +0 -0
  2. lfx/__main__.py +25 -0
  3. lfx/_assets/component_index.json +1 -0
  4. lfx/base/__init__.py +0 -0
  5. lfx/base/agents/__init__.py +0 -0
  6. lfx/base/agents/agent.py +375 -0
  7. lfx/base/agents/altk_base_agent.py +380 -0
  8. lfx/base/agents/altk_tool_wrappers.py +565 -0
  9. lfx/base/agents/callback.py +130 -0
  10. lfx/base/agents/context.py +109 -0
  11. lfx/base/agents/crewai/__init__.py +0 -0
  12. lfx/base/agents/crewai/crew.py +231 -0
  13. lfx/base/agents/crewai/tasks.py +12 -0
  14. lfx/base/agents/default_prompts.py +23 -0
  15. lfx/base/agents/errors.py +15 -0
  16. lfx/base/agents/events.py +430 -0
  17. lfx/base/agents/utils.py +237 -0
  18. lfx/base/astra_assistants/__init__.py +0 -0
  19. lfx/base/astra_assistants/util.py +171 -0
  20. lfx/base/chains/__init__.py +0 -0
  21. lfx/base/chains/model.py +19 -0
  22. lfx/base/composio/__init__.py +0 -0
  23. lfx/base/composio/composio_base.py +2584 -0
  24. lfx/base/compressors/__init__.py +0 -0
  25. lfx/base/compressors/model.py +60 -0
  26. lfx/base/constants.py +46 -0
  27. lfx/base/curl/__init__.py +0 -0
  28. lfx/base/curl/parse.py +188 -0
  29. lfx/base/data/__init__.py +5 -0
  30. lfx/base/data/base_file.py +810 -0
  31. lfx/base/data/docling_utils.py +338 -0
  32. lfx/base/data/storage_utils.py +192 -0
  33. lfx/base/data/utils.py +362 -0
  34. lfx/base/datastax/__init__.py +5 -0
  35. lfx/base/datastax/astradb_base.py +896 -0
  36. lfx/base/document_transformers/__init__.py +0 -0
  37. lfx/base/document_transformers/model.py +43 -0
  38. lfx/base/embeddings/__init__.py +0 -0
  39. lfx/base/embeddings/aiml_embeddings.py +62 -0
  40. lfx/base/embeddings/embeddings_class.py +113 -0
  41. lfx/base/embeddings/model.py +26 -0
  42. lfx/base/flow_processing/__init__.py +0 -0
  43. lfx/base/flow_processing/utils.py +86 -0
  44. lfx/base/huggingface/__init__.py +0 -0
  45. lfx/base/huggingface/model_bridge.py +133 -0
  46. lfx/base/io/__init__.py +0 -0
  47. lfx/base/io/chat.py +21 -0
  48. lfx/base/io/text.py +22 -0
  49. lfx/base/knowledge_bases/__init__.py +3 -0
  50. lfx/base/knowledge_bases/knowledge_base_utils.py +137 -0
  51. lfx/base/langchain_utilities/__init__.py +0 -0
  52. lfx/base/langchain_utilities/model.py +35 -0
  53. lfx/base/langchain_utilities/spider_constants.py +1 -0
  54. lfx/base/langwatch/__init__.py +0 -0
  55. lfx/base/langwatch/utils.py +18 -0
  56. lfx/base/mcp/__init__.py +0 -0
  57. lfx/base/mcp/constants.py +2 -0
  58. lfx/base/mcp/util.py +1659 -0
  59. lfx/base/memory/__init__.py +0 -0
  60. lfx/base/memory/memory.py +49 -0
  61. lfx/base/memory/model.py +38 -0
  62. lfx/base/models/__init__.py +3 -0
  63. lfx/base/models/aiml_constants.py +51 -0
  64. lfx/base/models/anthropic_constants.py +51 -0
  65. lfx/base/models/aws_constants.py +151 -0
  66. lfx/base/models/chat_result.py +76 -0
  67. lfx/base/models/cometapi_constants.py +54 -0
  68. lfx/base/models/google_generative_ai_constants.py +70 -0
  69. lfx/base/models/google_generative_ai_model.py +38 -0
  70. lfx/base/models/groq_constants.py +150 -0
  71. lfx/base/models/groq_model_discovery.py +265 -0
  72. lfx/base/models/model.py +375 -0
  73. lfx/base/models/model_input_constants.py +378 -0
  74. lfx/base/models/model_metadata.py +41 -0
  75. lfx/base/models/model_utils.py +108 -0
  76. lfx/base/models/novita_constants.py +35 -0
  77. lfx/base/models/ollama_constants.py +52 -0
  78. lfx/base/models/openai_constants.py +129 -0
  79. lfx/base/models/sambanova_constants.py +18 -0
  80. lfx/base/models/watsonx_constants.py +36 -0
  81. lfx/base/processing/__init__.py +0 -0
  82. lfx/base/prompts/__init__.py +0 -0
  83. lfx/base/prompts/api_utils.py +224 -0
  84. lfx/base/prompts/utils.py +61 -0
  85. lfx/base/textsplitters/__init__.py +0 -0
  86. lfx/base/textsplitters/model.py +28 -0
  87. lfx/base/tools/__init__.py +0 -0
  88. lfx/base/tools/base.py +26 -0
  89. lfx/base/tools/component_tool.py +325 -0
  90. lfx/base/tools/constants.py +49 -0
  91. lfx/base/tools/flow_tool.py +132 -0
  92. lfx/base/tools/run_flow.py +698 -0
  93. lfx/base/vectorstores/__init__.py +0 -0
  94. lfx/base/vectorstores/model.py +193 -0
  95. lfx/base/vectorstores/utils.py +22 -0
  96. lfx/base/vectorstores/vector_store_connection_decorator.py +52 -0
  97. lfx/cli/__init__.py +5 -0
  98. lfx/cli/commands.py +327 -0
  99. lfx/cli/common.py +650 -0
  100. lfx/cli/run.py +506 -0
  101. lfx/cli/script_loader.py +289 -0
  102. lfx/cli/serve_app.py +546 -0
  103. lfx/cli/validation.py +69 -0
  104. lfx/components/FAISS/__init__.py +34 -0
  105. lfx/components/FAISS/faiss.py +111 -0
  106. lfx/components/Notion/__init__.py +19 -0
  107. lfx/components/Notion/add_content_to_page.py +269 -0
  108. lfx/components/Notion/create_page.py +94 -0
  109. lfx/components/Notion/list_database_properties.py +68 -0
  110. lfx/components/Notion/list_pages.py +122 -0
  111. lfx/components/Notion/list_users.py +77 -0
  112. lfx/components/Notion/page_content_viewer.py +93 -0
  113. lfx/components/Notion/search.py +111 -0
  114. lfx/components/Notion/update_page_property.py +114 -0
  115. lfx/components/__init__.py +428 -0
  116. lfx/components/_importing.py +42 -0
  117. lfx/components/agentql/__init__.py +3 -0
  118. lfx/components/agentql/agentql_api.py +151 -0
  119. lfx/components/aiml/__init__.py +37 -0
  120. lfx/components/aiml/aiml.py +115 -0
  121. lfx/components/aiml/aiml_embeddings.py +37 -0
  122. lfx/components/altk/__init__.py +34 -0
  123. lfx/components/altk/altk_agent.py +193 -0
  124. lfx/components/amazon/__init__.py +36 -0
  125. lfx/components/amazon/amazon_bedrock_converse.py +195 -0
  126. lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
  127. lfx/components/amazon/amazon_bedrock_model.py +130 -0
  128. lfx/components/amazon/s3_bucket_uploader.py +211 -0
  129. lfx/components/anthropic/__init__.py +34 -0
  130. lfx/components/anthropic/anthropic.py +187 -0
  131. lfx/components/apify/__init__.py +5 -0
  132. lfx/components/apify/apify_actor.py +325 -0
  133. lfx/components/arxiv/__init__.py +3 -0
  134. lfx/components/arxiv/arxiv.py +169 -0
  135. lfx/components/assemblyai/__init__.py +46 -0
  136. lfx/components/assemblyai/assemblyai_get_subtitles.py +83 -0
  137. lfx/components/assemblyai/assemblyai_lemur.py +183 -0
  138. lfx/components/assemblyai/assemblyai_list_transcripts.py +95 -0
  139. lfx/components/assemblyai/assemblyai_poll_transcript.py +72 -0
  140. lfx/components/assemblyai/assemblyai_start_transcript.py +188 -0
  141. lfx/components/azure/__init__.py +37 -0
  142. lfx/components/azure/azure_openai.py +95 -0
  143. lfx/components/azure/azure_openai_embeddings.py +83 -0
  144. lfx/components/baidu/__init__.py +32 -0
  145. lfx/components/baidu/baidu_qianfan_chat.py +113 -0
  146. lfx/components/bing/__init__.py +3 -0
  147. lfx/components/bing/bing_search_api.py +61 -0
  148. lfx/components/cassandra/__init__.py +40 -0
  149. lfx/components/cassandra/cassandra.py +264 -0
  150. lfx/components/cassandra/cassandra_chat.py +92 -0
  151. lfx/components/cassandra/cassandra_graph.py +238 -0
  152. lfx/components/chains/__init__.py +3 -0
  153. lfx/components/chroma/__init__.py +34 -0
  154. lfx/components/chroma/chroma.py +169 -0
  155. lfx/components/cleanlab/__init__.py +40 -0
  156. lfx/components/cleanlab/cleanlab_evaluator.py +155 -0
  157. lfx/components/cleanlab/cleanlab_rag_evaluator.py +254 -0
  158. lfx/components/cleanlab/cleanlab_remediator.py +131 -0
  159. lfx/components/clickhouse/__init__.py +34 -0
  160. lfx/components/clickhouse/clickhouse.py +135 -0
  161. lfx/components/cloudflare/__init__.py +32 -0
  162. lfx/components/cloudflare/cloudflare.py +81 -0
  163. lfx/components/cohere/__init__.py +40 -0
  164. lfx/components/cohere/cohere_embeddings.py +81 -0
  165. lfx/components/cohere/cohere_models.py +46 -0
  166. lfx/components/cohere/cohere_rerank.py +51 -0
  167. lfx/components/cometapi/__init__.py +32 -0
  168. lfx/components/cometapi/cometapi.py +166 -0
  169. lfx/components/composio/__init__.py +222 -0
  170. lfx/components/composio/agentql_composio.py +11 -0
  171. lfx/components/composio/agiled_composio.py +11 -0
  172. lfx/components/composio/airtable_composio.py +11 -0
  173. lfx/components/composio/apollo_composio.py +11 -0
  174. lfx/components/composio/asana_composio.py +11 -0
  175. lfx/components/composio/attio_composio.py +11 -0
  176. lfx/components/composio/bitbucket_composio.py +11 -0
  177. lfx/components/composio/bolna_composio.py +11 -0
  178. lfx/components/composio/brightdata_composio.py +11 -0
  179. lfx/components/composio/calendly_composio.py +11 -0
  180. lfx/components/composio/canva_composio.py +11 -0
  181. lfx/components/composio/canvas_composio.py +11 -0
  182. lfx/components/composio/coda_composio.py +11 -0
  183. lfx/components/composio/composio_api.py +278 -0
  184. lfx/components/composio/contentful_composio.py +11 -0
  185. lfx/components/composio/digicert_composio.py +11 -0
  186. lfx/components/composio/discord_composio.py +11 -0
  187. lfx/components/composio/dropbox_compnent.py +11 -0
  188. lfx/components/composio/elevenlabs_composio.py +11 -0
  189. lfx/components/composio/exa_composio.py +11 -0
  190. lfx/components/composio/figma_composio.py +11 -0
  191. lfx/components/composio/finage_composio.py +11 -0
  192. lfx/components/composio/firecrawl_composio.py +11 -0
  193. lfx/components/composio/fireflies_composio.py +11 -0
  194. lfx/components/composio/fixer_composio.py +11 -0
  195. lfx/components/composio/flexisign_composio.py +11 -0
  196. lfx/components/composio/freshdesk_composio.py +11 -0
  197. lfx/components/composio/github_composio.py +11 -0
  198. lfx/components/composio/gmail_composio.py +38 -0
  199. lfx/components/composio/googlebigquery_composio.py +11 -0
  200. lfx/components/composio/googlecalendar_composio.py +11 -0
  201. lfx/components/composio/googleclassroom_composio.py +11 -0
  202. lfx/components/composio/googledocs_composio.py +11 -0
  203. lfx/components/composio/googlemeet_composio.py +11 -0
  204. lfx/components/composio/googlesheets_composio.py +11 -0
  205. lfx/components/composio/googletasks_composio.py +8 -0
  206. lfx/components/composio/heygen_composio.py +11 -0
  207. lfx/components/composio/instagram_composio.py +11 -0
  208. lfx/components/composio/jira_composio.py +11 -0
  209. lfx/components/composio/jotform_composio.py +11 -0
  210. lfx/components/composio/klaviyo_composio.py +11 -0
  211. lfx/components/composio/linear_composio.py +11 -0
  212. lfx/components/composio/listennotes_composio.py +11 -0
  213. lfx/components/composio/mem0_composio.py +11 -0
  214. lfx/components/composio/miro_composio.py +11 -0
  215. lfx/components/composio/missive_composio.py +11 -0
  216. lfx/components/composio/notion_composio.py +11 -0
  217. lfx/components/composio/onedrive_composio.py +11 -0
  218. lfx/components/composio/outlook_composio.py +11 -0
  219. lfx/components/composio/pandadoc_composio.py +11 -0
  220. lfx/components/composio/peopledatalabs_composio.py +11 -0
  221. lfx/components/composio/perplexityai_composio.py +11 -0
  222. lfx/components/composio/reddit_composio.py +11 -0
  223. lfx/components/composio/serpapi_composio.py +11 -0
  224. lfx/components/composio/slack_composio.py +11 -0
  225. lfx/components/composio/slackbot_composio.py +11 -0
  226. lfx/components/composio/snowflake_composio.py +11 -0
  227. lfx/components/composio/supabase_composio.py +11 -0
  228. lfx/components/composio/tavily_composio.py +11 -0
  229. lfx/components/composio/timelinesai_composio.py +11 -0
  230. lfx/components/composio/todoist_composio.py +11 -0
  231. lfx/components/composio/wrike_composio.py +11 -0
  232. lfx/components/composio/youtube_composio.py +11 -0
  233. lfx/components/confluence/__init__.py +3 -0
  234. lfx/components/confluence/confluence.py +84 -0
  235. lfx/components/couchbase/__init__.py +34 -0
  236. lfx/components/couchbase/couchbase.py +102 -0
  237. lfx/components/crewai/__init__.py +49 -0
  238. lfx/components/crewai/crewai.py +108 -0
  239. lfx/components/crewai/hierarchical_crew.py +47 -0
  240. lfx/components/crewai/hierarchical_task.py +45 -0
  241. lfx/components/crewai/sequential_crew.py +53 -0
  242. lfx/components/crewai/sequential_task.py +74 -0
  243. lfx/components/crewai/sequential_task_agent.py +144 -0
  244. lfx/components/cuga/__init__.py +34 -0
  245. lfx/components/cuga/cuga_agent.py +730 -0
  246. lfx/components/custom_component/__init__.py +34 -0
  247. lfx/components/custom_component/custom_component.py +31 -0
  248. lfx/components/data/__init__.py +114 -0
  249. lfx/components/data_source/__init__.py +58 -0
  250. lfx/components/data_source/api_request.py +577 -0
  251. lfx/components/data_source/csv_to_data.py +101 -0
  252. lfx/components/data_source/json_to_data.py +106 -0
  253. lfx/components/data_source/mock_data.py +398 -0
  254. lfx/components/data_source/news_search.py +166 -0
  255. lfx/components/data_source/rss.py +71 -0
  256. lfx/components/data_source/sql_executor.py +101 -0
  257. lfx/components/data_source/url.py +311 -0
  258. lfx/components/data_source/web_search.py +326 -0
  259. lfx/components/datastax/__init__.py +76 -0
  260. lfx/components/datastax/astradb_assistant_manager.py +307 -0
  261. lfx/components/datastax/astradb_chatmemory.py +40 -0
  262. lfx/components/datastax/astradb_cql.py +288 -0
  263. lfx/components/datastax/astradb_graph.py +217 -0
  264. lfx/components/datastax/astradb_tool.py +378 -0
  265. lfx/components/datastax/astradb_vectorize.py +122 -0
  266. lfx/components/datastax/astradb_vectorstore.py +449 -0
  267. lfx/components/datastax/create_assistant.py +59 -0
  268. lfx/components/datastax/create_thread.py +33 -0
  269. lfx/components/datastax/dotenv.py +36 -0
  270. lfx/components/datastax/get_assistant.py +38 -0
  271. lfx/components/datastax/getenvvar.py +31 -0
  272. lfx/components/datastax/graph_rag.py +141 -0
  273. lfx/components/datastax/hcd.py +315 -0
  274. lfx/components/datastax/list_assistants.py +26 -0
  275. lfx/components/datastax/run.py +90 -0
  276. lfx/components/deactivated/__init__.py +15 -0
  277. lfx/components/deactivated/amazon_kendra.py +66 -0
  278. lfx/components/deactivated/chat_litellm_model.py +158 -0
  279. lfx/components/deactivated/code_block_extractor.py +26 -0
  280. lfx/components/deactivated/documents_to_data.py +22 -0
  281. lfx/components/deactivated/embed.py +16 -0
  282. lfx/components/deactivated/extract_key_from_data.py +46 -0
  283. lfx/components/deactivated/json_document_builder.py +57 -0
  284. lfx/components/deactivated/list_flows.py +20 -0
  285. lfx/components/deactivated/mcp_sse.py +61 -0
  286. lfx/components/deactivated/mcp_stdio.py +62 -0
  287. lfx/components/deactivated/merge_data.py +93 -0
  288. lfx/components/deactivated/message.py +37 -0
  289. lfx/components/deactivated/metal.py +54 -0
  290. lfx/components/deactivated/multi_query.py +59 -0
  291. lfx/components/deactivated/retriever.py +43 -0
  292. lfx/components/deactivated/selective_passthrough.py +77 -0
  293. lfx/components/deactivated/should_run_next.py +40 -0
  294. lfx/components/deactivated/split_text.py +63 -0
  295. lfx/components/deactivated/store_message.py +24 -0
  296. lfx/components/deactivated/sub_flow.py +124 -0
  297. lfx/components/deactivated/vectara_self_query.py +76 -0
  298. lfx/components/deactivated/vector_store.py +24 -0
  299. lfx/components/deepseek/__init__.py +34 -0
  300. lfx/components/deepseek/deepseek.py +136 -0
  301. lfx/components/docling/__init__.py +43 -0
  302. lfx/components/docling/chunk_docling_document.py +186 -0
  303. lfx/components/docling/docling_inline.py +238 -0
  304. lfx/components/docling/docling_remote.py +195 -0
  305. lfx/components/docling/export_docling_document.py +117 -0
  306. lfx/components/documentloaders/__init__.py +3 -0
  307. lfx/components/duckduckgo/__init__.py +3 -0
  308. lfx/components/duckduckgo/duck_duck_go_search_run.py +92 -0
  309. lfx/components/elastic/__init__.py +37 -0
  310. lfx/components/elastic/elasticsearch.py +267 -0
  311. lfx/components/elastic/opensearch.py +789 -0
  312. lfx/components/elastic/opensearch_multimodal.py +1575 -0
  313. lfx/components/embeddings/__init__.py +37 -0
  314. lfx/components/embeddings/similarity.py +77 -0
  315. lfx/components/embeddings/text_embedder.py +65 -0
  316. lfx/components/exa/__init__.py +3 -0
  317. lfx/components/exa/exa_search.py +68 -0
  318. lfx/components/files_and_knowledge/__init__.py +47 -0
  319. lfx/components/files_and_knowledge/directory.py +113 -0
  320. lfx/components/files_and_knowledge/file.py +841 -0
  321. lfx/components/files_and_knowledge/ingestion.py +694 -0
  322. lfx/components/files_and_knowledge/retrieval.py +264 -0
  323. lfx/components/files_and_knowledge/save_file.py +746 -0
  324. lfx/components/firecrawl/__init__.py +43 -0
  325. lfx/components/firecrawl/firecrawl_crawl_api.py +88 -0
  326. lfx/components/firecrawl/firecrawl_extract_api.py +136 -0
  327. lfx/components/firecrawl/firecrawl_map_api.py +89 -0
  328. lfx/components/firecrawl/firecrawl_scrape_api.py +73 -0
  329. lfx/components/flow_controls/__init__.py +58 -0
  330. lfx/components/flow_controls/conditional_router.py +208 -0
  331. lfx/components/flow_controls/data_conditional_router.py +126 -0
  332. lfx/components/flow_controls/flow_tool.py +111 -0
  333. lfx/components/flow_controls/listen.py +29 -0
  334. lfx/components/flow_controls/loop.py +163 -0
  335. lfx/components/flow_controls/notify.py +88 -0
  336. lfx/components/flow_controls/pass_message.py +36 -0
  337. lfx/components/flow_controls/run_flow.py +108 -0
  338. lfx/components/flow_controls/sub_flow.py +115 -0
  339. lfx/components/git/__init__.py +4 -0
  340. lfx/components/git/git.py +262 -0
  341. lfx/components/git/gitextractor.py +196 -0
  342. lfx/components/glean/__init__.py +3 -0
  343. lfx/components/glean/glean_search_api.py +173 -0
  344. lfx/components/google/__init__.py +17 -0
  345. lfx/components/google/gmail.py +193 -0
  346. lfx/components/google/google_bq_sql_executor.py +157 -0
  347. lfx/components/google/google_drive.py +92 -0
  348. lfx/components/google/google_drive_search.py +152 -0
  349. lfx/components/google/google_generative_ai.py +144 -0
  350. lfx/components/google/google_generative_ai_embeddings.py +141 -0
  351. lfx/components/google/google_oauth_token.py +89 -0
  352. lfx/components/google/google_search_api_core.py +68 -0
  353. lfx/components/google/google_serper_api_core.py +74 -0
  354. lfx/components/groq/__init__.py +34 -0
  355. lfx/components/groq/groq.py +143 -0
  356. lfx/components/helpers/__init__.py +154 -0
  357. lfx/components/homeassistant/__init__.py +7 -0
  358. lfx/components/homeassistant/home_assistant_control.py +152 -0
  359. lfx/components/homeassistant/list_home_assistant_states.py +137 -0
  360. lfx/components/huggingface/__init__.py +37 -0
  361. lfx/components/huggingface/huggingface.py +199 -0
  362. lfx/components/huggingface/huggingface_inference_api.py +106 -0
  363. lfx/components/ibm/__init__.py +34 -0
  364. lfx/components/ibm/watsonx.py +207 -0
  365. lfx/components/ibm/watsonx_embeddings.py +135 -0
  366. lfx/components/icosacomputing/__init__.py +5 -0
  367. lfx/components/icosacomputing/combinatorial_reasoner.py +84 -0
  368. lfx/components/input_output/__init__.py +40 -0
  369. lfx/components/input_output/chat.py +109 -0
  370. lfx/components/input_output/chat_output.py +184 -0
  371. lfx/components/input_output/text.py +27 -0
  372. lfx/components/input_output/text_output.py +29 -0
  373. lfx/components/input_output/webhook.py +56 -0
  374. lfx/components/jigsawstack/__init__.py +23 -0
  375. lfx/components/jigsawstack/ai_scrape.py +126 -0
  376. lfx/components/jigsawstack/ai_web_search.py +136 -0
  377. lfx/components/jigsawstack/file_read.py +115 -0
  378. lfx/components/jigsawstack/file_upload.py +94 -0
  379. lfx/components/jigsawstack/image_generation.py +205 -0
  380. lfx/components/jigsawstack/nsfw.py +60 -0
  381. lfx/components/jigsawstack/object_detection.py +124 -0
  382. lfx/components/jigsawstack/sentiment.py +112 -0
  383. lfx/components/jigsawstack/text_to_sql.py +90 -0
  384. lfx/components/jigsawstack/text_translate.py +77 -0
  385. lfx/components/jigsawstack/vocr.py +107 -0
  386. lfx/components/knowledge_bases/__init__.py +89 -0
  387. lfx/components/langchain_utilities/__init__.py +109 -0
  388. lfx/components/langchain_utilities/character.py +53 -0
  389. lfx/components/langchain_utilities/conversation.py +59 -0
  390. lfx/components/langchain_utilities/csv_agent.py +175 -0
  391. lfx/components/langchain_utilities/fake_embeddings.py +26 -0
  392. lfx/components/langchain_utilities/html_link_extractor.py +35 -0
  393. lfx/components/langchain_utilities/json_agent.py +100 -0
  394. lfx/components/langchain_utilities/langchain_hub.py +126 -0
  395. lfx/components/langchain_utilities/language_recursive.py +49 -0
  396. lfx/components/langchain_utilities/language_semantic.py +138 -0
  397. lfx/components/langchain_utilities/llm_checker.py +39 -0
  398. lfx/components/langchain_utilities/llm_math.py +42 -0
  399. lfx/components/langchain_utilities/natural_language.py +61 -0
  400. lfx/components/langchain_utilities/openai_tools.py +53 -0
  401. lfx/components/langchain_utilities/openapi.py +48 -0
  402. lfx/components/langchain_utilities/recursive_character.py +60 -0
  403. lfx/components/langchain_utilities/retrieval_qa.py +83 -0
  404. lfx/components/langchain_utilities/runnable_executor.py +137 -0
  405. lfx/components/langchain_utilities/self_query.py +80 -0
  406. lfx/components/langchain_utilities/spider.py +142 -0
  407. lfx/components/langchain_utilities/sql.py +40 -0
  408. lfx/components/langchain_utilities/sql_database.py +35 -0
  409. lfx/components/langchain_utilities/sql_generator.py +78 -0
  410. lfx/components/langchain_utilities/tool_calling.py +59 -0
  411. lfx/components/langchain_utilities/vector_store_info.py +49 -0
  412. lfx/components/langchain_utilities/vector_store_router.py +33 -0
  413. lfx/components/langchain_utilities/xml_agent.py +71 -0
  414. lfx/components/langwatch/__init__.py +3 -0
  415. lfx/components/langwatch/langwatch.py +278 -0
  416. lfx/components/link_extractors/__init__.py +3 -0
  417. lfx/components/llm_operations/__init__.py +46 -0
  418. lfx/components/llm_operations/batch_run.py +205 -0
  419. lfx/components/llm_operations/lambda_filter.py +218 -0
  420. lfx/components/llm_operations/llm_conditional_router.py +421 -0
  421. lfx/components/llm_operations/llm_selector.py +499 -0
  422. lfx/components/llm_operations/structured_output.py +244 -0
  423. lfx/components/lmstudio/__init__.py +34 -0
  424. lfx/components/lmstudio/lmstudioembeddings.py +89 -0
  425. lfx/components/lmstudio/lmstudiomodel.py +133 -0
  426. lfx/components/logic/__init__.py +181 -0
  427. lfx/components/maritalk/__init__.py +32 -0
  428. lfx/components/maritalk/maritalk.py +52 -0
  429. lfx/components/mem0/__init__.py +3 -0
  430. lfx/components/mem0/mem0_chat_memory.py +147 -0
  431. lfx/components/milvus/__init__.py +34 -0
  432. lfx/components/milvus/milvus.py +115 -0
  433. lfx/components/mistral/__init__.py +37 -0
  434. lfx/components/mistral/mistral.py +114 -0
  435. lfx/components/mistral/mistral_embeddings.py +58 -0
  436. lfx/components/models/__init__.py +89 -0
  437. lfx/components/models_and_agents/__init__.py +49 -0
  438. lfx/components/models_and_agents/agent.py +644 -0
  439. lfx/components/models_and_agents/embedding_model.py +423 -0
  440. lfx/components/models_and_agents/language_model.py +398 -0
  441. lfx/components/models_and_agents/mcp_component.py +594 -0
  442. lfx/components/models_and_agents/memory.py +268 -0
  443. lfx/components/models_and_agents/prompt.py +67 -0
  444. lfx/components/mongodb/__init__.py +34 -0
  445. lfx/components/mongodb/mongodb_atlas.py +213 -0
  446. lfx/components/needle/__init__.py +3 -0
  447. lfx/components/needle/needle.py +104 -0
  448. lfx/components/notdiamond/__init__.py +34 -0
  449. lfx/components/notdiamond/notdiamond.py +228 -0
  450. lfx/components/novita/__init__.py +32 -0
  451. lfx/components/novita/novita.py +130 -0
  452. lfx/components/nvidia/__init__.py +57 -0
  453. lfx/components/nvidia/nvidia.py +151 -0
  454. lfx/components/nvidia/nvidia_embedding.py +77 -0
  455. lfx/components/nvidia/nvidia_ingest.py +317 -0
  456. lfx/components/nvidia/nvidia_rerank.py +63 -0
  457. lfx/components/nvidia/system_assist.py +65 -0
  458. lfx/components/olivya/__init__.py +3 -0
  459. lfx/components/olivya/olivya.py +116 -0
  460. lfx/components/ollama/__init__.py +37 -0
  461. lfx/components/ollama/ollama.py +548 -0
  462. lfx/components/ollama/ollama_embeddings.py +103 -0
  463. lfx/components/openai/__init__.py +37 -0
  464. lfx/components/openai/openai.py +100 -0
  465. lfx/components/openai/openai_chat_model.py +176 -0
  466. lfx/components/openrouter/__init__.py +32 -0
  467. lfx/components/openrouter/openrouter.py +104 -0
  468. lfx/components/output_parsers/__init__.py +3 -0
  469. lfx/components/perplexity/__init__.py +34 -0
  470. lfx/components/perplexity/perplexity.py +75 -0
  471. lfx/components/pgvector/__init__.py +34 -0
  472. lfx/components/pgvector/pgvector.py +72 -0
  473. lfx/components/pinecone/__init__.py +34 -0
  474. lfx/components/pinecone/pinecone.py +134 -0
  475. lfx/components/processing/__init__.py +72 -0
  476. lfx/components/processing/alter_metadata.py +109 -0
  477. lfx/components/processing/combine_text.py +40 -0
  478. lfx/components/processing/converter.py +248 -0
  479. lfx/components/processing/create_data.py +111 -0
  480. lfx/components/processing/create_list.py +40 -0
  481. lfx/components/processing/data_operations.py +528 -0
  482. lfx/components/processing/data_to_dataframe.py +71 -0
  483. lfx/components/processing/dataframe_operations.py +313 -0
  484. lfx/components/processing/dataframe_to_toolset.py +259 -0
  485. lfx/components/processing/dynamic_create_data.py +357 -0
  486. lfx/components/processing/extract_key.py +54 -0
  487. lfx/components/processing/filter_data.py +43 -0
  488. lfx/components/processing/filter_data_values.py +89 -0
  489. lfx/components/processing/json_cleaner.py +104 -0
  490. lfx/components/processing/merge_data.py +91 -0
  491. lfx/components/processing/message_to_data.py +37 -0
  492. lfx/components/processing/output_parser.py +46 -0
  493. lfx/components/processing/parse_data.py +71 -0
  494. lfx/components/processing/parse_dataframe.py +69 -0
  495. lfx/components/processing/parse_json_data.py +91 -0
  496. lfx/components/processing/parser.py +148 -0
  497. lfx/components/processing/regex.py +83 -0
  498. lfx/components/processing/select_data.py +49 -0
  499. lfx/components/processing/split_text.py +141 -0
  500. lfx/components/processing/store_message.py +91 -0
  501. lfx/components/processing/update_data.py +161 -0
  502. lfx/components/prototypes/__init__.py +35 -0
  503. lfx/components/prototypes/python_function.py +73 -0
  504. lfx/components/qdrant/__init__.py +34 -0
  505. lfx/components/qdrant/qdrant.py +109 -0
  506. lfx/components/redis/__init__.py +37 -0
  507. lfx/components/redis/redis.py +89 -0
  508. lfx/components/redis/redis_chat.py +43 -0
  509. lfx/components/sambanova/__init__.py +32 -0
  510. lfx/components/sambanova/sambanova.py +84 -0
  511. lfx/components/scrapegraph/__init__.py +40 -0
  512. lfx/components/scrapegraph/scrapegraph_markdownify_api.py +64 -0
  513. lfx/components/scrapegraph/scrapegraph_search_api.py +64 -0
  514. lfx/components/scrapegraph/scrapegraph_smart_scraper_api.py +71 -0
  515. lfx/components/searchapi/__init__.py +34 -0
  516. lfx/components/searchapi/search.py +79 -0
  517. lfx/components/serpapi/__init__.py +3 -0
  518. lfx/components/serpapi/serp.py +115 -0
  519. lfx/components/supabase/__init__.py +34 -0
  520. lfx/components/supabase/supabase.py +76 -0
  521. lfx/components/tavily/__init__.py +4 -0
  522. lfx/components/tavily/tavily_extract.py +117 -0
  523. lfx/components/tavily/tavily_search.py +212 -0
  524. lfx/components/textsplitters/__init__.py +3 -0
  525. lfx/components/toolkits/__init__.py +3 -0
  526. lfx/components/tools/__init__.py +66 -0
  527. lfx/components/tools/calculator.py +109 -0
  528. lfx/components/tools/google_search_api.py +45 -0
  529. lfx/components/tools/google_serper_api.py +115 -0
  530. lfx/components/tools/python_code_structured_tool.py +328 -0
  531. lfx/components/tools/python_repl.py +98 -0
  532. lfx/components/tools/search_api.py +88 -0
  533. lfx/components/tools/searxng.py +145 -0
  534. lfx/components/tools/serp_api.py +120 -0
  535. lfx/components/tools/tavily_search_tool.py +345 -0
  536. lfx/components/tools/wikidata_api.py +103 -0
  537. lfx/components/tools/wikipedia_api.py +50 -0
  538. lfx/components/tools/yahoo_finance.py +130 -0
  539. lfx/components/twelvelabs/__init__.py +52 -0
  540. lfx/components/twelvelabs/convert_astra_results.py +84 -0
  541. lfx/components/twelvelabs/pegasus_index.py +311 -0
  542. lfx/components/twelvelabs/split_video.py +301 -0
  543. lfx/components/twelvelabs/text_embeddings.py +57 -0
  544. lfx/components/twelvelabs/twelvelabs_pegasus.py +408 -0
  545. lfx/components/twelvelabs/video_embeddings.py +100 -0
  546. lfx/components/twelvelabs/video_file.py +191 -0
  547. lfx/components/unstructured/__init__.py +3 -0
  548. lfx/components/unstructured/unstructured.py +121 -0
  549. lfx/components/upstash/__init__.py +34 -0
  550. lfx/components/upstash/upstash.py +124 -0
  551. lfx/components/utilities/__init__.py +43 -0
  552. lfx/components/utilities/calculator_core.py +89 -0
  553. lfx/components/utilities/current_date.py +42 -0
  554. lfx/components/utilities/id_generator.py +42 -0
  555. lfx/components/utilities/python_repl_core.py +98 -0
  556. lfx/components/vectara/__init__.py +37 -0
  557. lfx/components/vectara/vectara.py +97 -0
  558. lfx/components/vectara/vectara_rag.py +164 -0
  559. lfx/components/vectorstores/__init__.py +34 -0
  560. lfx/components/vectorstores/local_db.py +270 -0
  561. lfx/components/vertexai/__init__.py +37 -0
  562. lfx/components/vertexai/vertexai.py +71 -0
  563. lfx/components/vertexai/vertexai_embeddings.py +67 -0
  564. lfx/components/vlmrun/__init__.py +34 -0
  565. lfx/components/vlmrun/vlmrun_transcription.py +224 -0
  566. lfx/components/weaviate/__init__.py +34 -0
  567. lfx/components/weaviate/weaviate.py +89 -0
  568. lfx/components/wikipedia/__init__.py +4 -0
  569. lfx/components/wikipedia/wikidata.py +86 -0
  570. lfx/components/wikipedia/wikipedia.py +53 -0
  571. lfx/components/wolframalpha/__init__.py +3 -0
  572. lfx/components/wolframalpha/wolfram_alpha_api.py +54 -0
  573. lfx/components/xai/__init__.py +32 -0
  574. lfx/components/xai/xai.py +167 -0
  575. lfx/components/yahoosearch/__init__.py +3 -0
  576. lfx/components/yahoosearch/yahoo.py +137 -0
  577. lfx/components/youtube/__init__.py +52 -0
  578. lfx/components/youtube/channel.py +227 -0
  579. lfx/components/youtube/comments.py +231 -0
  580. lfx/components/youtube/playlist.py +33 -0
  581. lfx/components/youtube/search.py +120 -0
  582. lfx/components/youtube/trending.py +285 -0
  583. lfx/components/youtube/video_details.py +263 -0
  584. lfx/components/youtube/youtube_transcripts.py +206 -0
  585. lfx/components/zep/__init__.py +3 -0
  586. lfx/components/zep/zep.py +45 -0
  587. lfx/constants.py +6 -0
  588. lfx/custom/__init__.py +7 -0
  589. lfx/custom/attributes.py +87 -0
  590. lfx/custom/code_parser/__init__.py +3 -0
  591. lfx/custom/code_parser/code_parser.py +361 -0
  592. lfx/custom/custom_component/__init__.py +0 -0
  593. lfx/custom/custom_component/base_component.py +128 -0
  594. lfx/custom/custom_component/component.py +1890 -0
  595. lfx/custom/custom_component/component_with_cache.py +8 -0
  596. lfx/custom/custom_component/custom_component.py +650 -0
  597. lfx/custom/dependency_analyzer.py +165 -0
  598. lfx/custom/directory_reader/__init__.py +3 -0
  599. lfx/custom/directory_reader/directory_reader.py +359 -0
  600. lfx/custom/directory_reader/utils.py +171 -0
  601. lfx/custom/eval.py +12 -0
  602. lfx/custom/schema.py +32 -0
  603. lfx/custom/tree_visitor.py +21 -0
  604. lfx/custom/utils.py +877 -0
  605. lfx/custom/validate.py +523 -0
  606. lfx/events/__init__.py +1 -0
  607. lfx/events/event_manager.py +110 -0
  608. lfx/exceptions/__init__.py +0 -0
  609. lfx/exceptions/component.py +15 -0
  610. lfx/field_typing/__init__.py +91 -0
  611. lfx/field_typing/constants.py +216 -0
  612. lfx/field_typing/range_spec.py +35 -0
  613. lfx/graph/__init__.py +6 -0
  614. lfx/graph/edge/__init__.py +0 -0
  615. lfx/graph/edge/base.py +300 -0
  616. lfx/graph/edge/schema.py +119 -0
  617. lfx/graph/edge/utils.py +0 -0
  618. lfx/graph/graph/__init__.py +0 -0
  619. lfx/graph/graph/ascii.py +202 -0
  620. lfx/graph/graph/base.py +2298 -0
  621. lfx/graph/graph/constants.py +63 -0
  622. lfx/graph/graph/runnable_vertices_manager.py +133 -0
  623. lfx/graph/graph/schema.py +53 -0
  624. lfx/graph/graph/state_model.py +66 -0
  625. lfx/graph/graph/utils.py +1024 -0
  626. lfx/graph/schema.py +75 -0
  627. lfx/graph/state/__init__.py +0 -0
  628. lfx/graph/state/model.py +250 -0
  629. lfx/graph/utils.py +206 -0
  630. lfx/graph/vertex/__init__.py +0 -0
  631. lfx/graph/vertex/base.py +826 -0
  632. lfx/graph/vertex/constants.py +0 -0
  633. lfx/graph/vertex/exceptions.py +4 -0
  634. lfx/graph/vertex/param_handler.py +316 -0
  635. lfx/graph/vertex/schema.py +26 -0
  636. lfx/graph/vertex/utils.py +19 -0
  637. lfx/graph/vertex/vertex_types.py +489 -0
  638. lfx/helpers/__init__.py +141 -0
  639. lfx/helpers/base_model.py +71 -0
  640. lfx/helpers/custom.py +13 -0
  641. lfx/helpers/data.py +167 -0
  642. lfx/helpers/flow.py +308 -0
  643. lfx/inputs/__init__.py +68 -0
  644. lfx/inputs/constants.py +2 -0
  645. lfx/inputs/input_mixin.py +352 -0
  646. lfx/inputs/inputs.py +718 -0
  647. lfx/inputs/validators.py +19 -0
  648. lfx/interface/__init__.py +6 -0
  649. lfx/interface/components.py +897 -0
  650. lfx/interface/importing/__init__.py +5 -0
  651. lfx/interface/importing/utils.py +39 -0
  652. lfx/interface/initialize/__init__.py +3 -0
  653. lfx/interface/initialize/loading.py +317 -0
  654. lfx/interface/listing.py +26 -0
  655. lfx/interface/run.py +16 -0
  656. lfx/interface/utils.py +111 -0
  657. lfx/io/__init__.py +63 -0
  658. lfx/io/schema.py +295 -0
  659. lfx/load/__init__.py +8 -0
  660. lfx/load/load.py +256 -0
  661. lfx/load/utils.py +99 -0
  662. lfx/log/__init__.py +5 -0
  663. lfx/log/logger.py +411 -0
  664. lfx/logging/__init__.py +11 -0
  665. lfx/logging/logger.py +24 -0
  666. lfx/memory/__init__.py +70 -0
  667. lfx/memory/stubs.py +302 -0
  668. lfx/processing/__init__.py +1 -0
  669. lfx/processing/process.py +238 -0
  670. lfx/processing/utils.py +25 -0
  671. lfx/py.typed +0 -0
  672. lfx/schema/__init__.py +66 -0
  673. lfx/schema/artifact.py +83 -0
  674. lfx/schema/content_block.py +62 -0
  675. lfx/schema/content_types.py +91 -0
  676. lfx/schema/cross_module.py +80 -0
  677. lfx/schema/data.py +309 -0
  678. lfx/schema/dataframe.py +210 -0
  679. lfx/schema/dotdict.py +74 -0
  680. lfx/schema/encoders.py +13 -0
  681. lfx/schema/graph.py +47 -0
  682. lfx/schema/image.py +184 -0
  683. lfx/schema/json_schema.py +186 -0
  684. lfx/schema/log.py +62 -0
  685. lfx/schema/message.py +493 -0
  686. lfx/schema/openai_responses_schemas.py +74 -0
  687. lfx/schema/properties.py +41 -0
  688. lfx/schema/schema.py +180 -0
  689. lfx/schema/serialize.py +13 -0
  690. lfx/schema/table.py +142 -0
  691. lfx/schema/validators.py +114 -0
  692. lfx/serialization/__init__.py +5 -0
  693. lfx/serialization/constants.py +2 -0
  694. lfx/serialization/serialization.py +314 -0
  695. lfx/services/__init__.py +26 -0
  696. lfx/services/base.py +28 -0
  697. lfx/services/cache/__init__.py +6 -0
  698. lfx/services/cache/base.py +183 -0
  699. lfx/services/cache/service.py +166 -0
  700. lfx/services/cache/utils.py +169 -0
  701. lfx/services/chat/__init__.py +1 -0
  702. lfx/services/chat/config.py +2 -0
  703. lfx/services/chat/schema.py +10 -0
  704. lfx/services/database/__init__.py +5 -0
  705. lfx/services/database/service.py +25 -0
  706. lfx/services/deps.py +194 -0
  707. lfx/services/factory.py +19 -0
  708. lfx/services/initialize.py +19 -0
  709. lfx/services/interfaces.py +103 -0
  710. lfx/services/manager.py +185 -0
  711. lfx/services/mcp_composer/__init__.py +6 -0
  712. lfx/services/mcp_composer/factory.py +16 -0
  713. lfx/services/mcp_composer/service.py +1441 -0
  714. lfx/services/schema.py +21 -0
  715. lfx/services/session.py +87 -0
  716. lfx/services/settings/__init__.py +3 -0
  717. lfx/services/settings/auth.py +133 -0
  718. lfx/services/settings/base.py +668 -0
  719. lfx/services/settings/constants.py +43 -0
  720. lfx/services/settings/factory.py +23 -0
  721. lfx/services/settings/feature_flags.py +11 -0
  722. lfx/services/settings/service.py +35 -0
  723. lfx/services/settings/utils.py +40 -0
  724. lfx/services/shared_component_cache/__init__.py +1 -0
  725. lfx/services/shared_component_cache/factory.py +30 -0
  726. lfx/services/shared_component_cache/service.py +9 -0
  727. lfx/services/storage/__init__.py +5 -0
  728. lfx/services/storage/local.py +185 -0
  729. lfx/services/storage/service.py +177 -0
  730. lfx/services/tracing/__init__.py +1 -0
  731. lfx/services/tracing/service.py +21 -0
  732. lfx/settings.py +6 -0
  733. lfx/template/__init__.py +6 -0
  734. lfx/template/field/__init__.py +0 -0
  735. lfx/template/field/base.py +260 -0
  736. lfx/template/field/prompt.py +15 -0
  737. lfx/template/frontend_node/__init__.py +6 -0
  738. lfx/template/frontend_node/base.py +214 -0
  739. lfx/template/frontend_node/constants.py +65 -0
  740. lfx/template/frontend_node/custom_components.py +79 -0
  741. lfx/template/template/__init__.py +0 -0
  742. lfx/template/template/base.py +100 -0
  743. lfx/template/utils.py +217 -0
  744. lfx/type_extraction/__init__.py +19 -0
  745. lfx/type_extraction/type_extraction.py +75 -0
  746. lfx/type_extraction.py +80 -0
  747. lfx/utils/__init__.py +1 -0
  748. lfx/utils/async_helpers.py +42 -0
  749. lfx/utils/component_utils.py +154 -0
  750. lfx/utils/concurrency.py +60 -0
  751. lfx/utils/connection_string_parser.py +11 -0
  752. lfx/utils/constants.py +233 -0
  753. lfx/utils/data_structure.py +212 -0
  754. lfx/utils/exceptions.py +22 -0
  755. lfx/utils/helpers.py +34 -0
  756. lfx/utils/image.py +79 -0
  757. lfx/utils/langflow_utils.py +52 -0
  758. lfx/utils/lazy_load.py +15 -0
  759. lfx/utils/request_utils.py +18 -0
  760. lfx/utils/schemas.py +139 -0
  761. lfx/utils/ssrf_protection.py +384 -0
  762. lfx/utils/util.py +626 -0
  763. lfx/utils/util_strings.py +56 -0
  764. lfx/utils/validate_cloud.py +26 -0
  765. lfx/utils/version.py +24 -0
  766. lfx_nightly-0.2.0.dev25.dist-info/METADATA +312 -0
  767. lfx_nightly-0.2.0.dev25.dist-info/RECORD +769 -0
  768. lfx_nightly-0.2.0.dev25.dist-info/WHEEL +4 -0
  769. lfx_nightly-0.2.0.dev25.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,897 @@
1
+ import asyncio
2
+ import hashlib
3
+ import importlib
4
+ import inspect
5
+ import json
6
+ import os
7
+ import pkgutil
8
+ import time
9
+ from pathlib import Path
10
+ from typing import TYPE_CHECKING, Any, Optional
11
+
12
+ import orjson
13
+
14
+ from lfx.constants import BASE_COMPONENTS_PATH
15
+ from lfx.custom.utils import abuild_custom_components, create_component_template
16
+ from lfx.log.logger import logger
17
+
18
+ if TYPE_CHECKING:
19
+ from lfx.services.settings.service import SettingsService
20
+
21
+ MIN_MODULE_PARTS = 2
22
+ EXPECTED_RESULT_LENGTH = 2 # Expected length of the tuple returned by _process_single_module
23
+
24
+
25
+ # Create a class to manage component cache instead of using globals
26
+ class ComponentCache:
27
+ def __init__(self):
28
+ """Initializes the component cache.
29
+
30
+ Creates empty storage for all component types and tracking of fully loaded components.
31
+ """
32
+ self.all_types_dict: dict[str, Any] | None = None
33
+ self.fully_loaded_components: dict[str, bool] = {}
34
+
35
+
36
+ # Singleton instance
37
+ component_cache = ComponentCache()
38
+
39
+
40
+ def _parse_dev_mode() -> tuple[bool, list[str] | None]:
41
+ """Parse LFX_DEV to determine dev mode and which modules to load.
42
+
43
+ Development mode must be explicitly enabled via the LFX_DEV environment variable.
44
+ When enabled, components are always rebuilt dynamically to reflect code changes.
45
+ When disabled or not set, the prebuilt index is used for fast startup.
46
+
47
+ Supports two modes:
48
+ - Boolean mode: LFX_DEV=1/true/yes loads all modules dynamically
49
+ - List mode: LFX_DEV=mistral,openai,anthropic loads only specified modules
50
+
51
+ Returns:
52
+ Tuple of (dev_mode_enabled, module_list)
53
+ - If module_list is None, load all modules
54
+ - If module_list is a list, only load those specific modules
55
+ """
56
+ lfx_dev = os.getenv("LFX_DEV", "").strip()
57
+ if not lfx_dev:
58
+ return (False, None)
59
+
60
+ # Boolean mode: "1", "true", "yes" enables dev mode
61
+ if lfx_dev.lower() in {"1", "true", "yes"}:
62
+ return (True, None) # Load all modules
63
+
64
+ # Boolean mode: "0", "false", "no" explicitly disables dev mode
65
+ if lfx_dev.lower() in {"0", "false", "no"}:
66
+ return (False, None)
67
+
68
+ # List mode: comma-separated values
69
+ modules = [m.strip().lower() for m in lfx_dev.split(",") if m.strip()]
70
+ if modules:
71
+ return (True, modules)
72
+
73
+ return (False, None)
74
+
75
+
76
+ def _read_component_index(custom_path: str | None = None) -> dict | None:
77
+ """Read and validate the prebuilt component index.
78
+
79
+ Args:
80
+ custom_path: Optional custom path or URL to index file. If None, uses built-in index.
81
+
82
+ Returns:
83
+ The index dictionary if valid, None otherwise
84
+ """
85
+ try:
86
+ import lfx
87
+
88
+ # Determine index location
89
+ if custom_path:
90
+ # Check if it's a URL
91
+ if custom_path.startswith(("http://", "https://")):
92
+ # Fetch from URL
93
+ import httpx
94
+
95
+ try:
96
+ response = httpx.get(custom_path, timeout=10.0)
97
+ response.raise_for_status()
98
+ blob = orjson.loads(response.content)
99
+ except httpx.HTTPError as e:
100
+ logger.warning(f"Failed to fetch component index from {custom_path}: {e}")
101
+ return None
102
+ except orjson.JSONDecodeError as e:
103
+ logger.warning(f"Component index from {custom_path} is corrupted or invalid JSON: {e}")
104
+ return None
105
+ else:
106
+ # Load from file path
107
+ index_path = Path(custom_path)
108
+ if not index_path.exists():
109
+ logger.warning(f"Custom component index not found at {custom_path}")
110
+ return None
111
+ try:
112
+ blob = orjson.loads(index_path.read_bytes())
113
+ except orjson.JSONDecodeError as e:
114
+ logger.warning(f"Component index at {custom_path} is corrupted or invalid JSON: {e}")
115
+ return None
116
+ else:
117
+ # Use built-in index
118
+ pkg_dir = Path(inspect.getfile(lfx)).parent
119
+ index_path = pkg_dir / "_assets" / "component_index.json"
120
+
121
+ if not index_path.exists():
122
+ return None
123
+
124
+ try:
125
+ blob = orjson.loads(index_path.read_bytes())
126
+ except orjson.JSONDecodeError as e:
127
+ logger.warning(f"Built-in component index is corrupted or invalid JSON: {e}")
128
+ return None
129
+
130
+ # Integrity check: verify SHA256
131
+ tmp = dict(blob)
132
+ sha = tmp.pop("sha256", None)
133
+ if not sha:
134
+ logger.warning("Component index missing SHA256 hash - index may be tampered")
135
+ return None
136
+
137
+ # Use orjson for hash calculation to match build script
138
+ calc = hashlib.sha256(orjson.dumps(tmp, option=orjson.OPT_SORT_KEYS)).hexdigest()
139
+ if sha != calc:
140
+ logger.warning(
141
+ "Component index integrity check failed - SHA256 mismatch (file may be corrupted or tampered)"
142
+ )
143
+ return None
144
+
145
+ # Version check: ensure index matches installed langflow version
146
+ from importlib.metadata import version
147
+
148
+ installed_version = version("langflow")
149
+ if blob.get("version") != installed_version:
150
+ logger.debug(
151
+ f"Component index version mismatch: index={blob.get('version')}, installed={installed_version}"
152
+ )
153
+ return None
154
+ except Exception as e: # noqa: BLE001
155
+ logger.warning(f"Unexpected error reading component index: {type(e).__name__}: {e}")
156
+ return None
157
+ return blob
158
+
159
+
160
+ def _get_cache_path() -> Path:
161
+ """Get the path for the cached component index in the user's cache directory."""
162
+ from platformdirs import user_cache_dir
163
+
164
+ cache_dir = Path(user_cache_dir("lfx", "langflow"))
165
+ cache_dir.mkdir(parents=True, exist_ok=True)
166
+ return cache_dir / "component_index.json"
167
+
168
+
169
+ def _save_generated_index(modules_dict: dict) -> None:
170
+ """Save a dynamically generated component index to cache for future use.
171
+
172
+ Args:
173
+ modules_dict: Dictionary of components by category
174
+ """
175
+ try:
176
+ cache_path = _get_cache_path()
177
+
178
+ # Convert modules_dict to entries format
179
+ entries = [[top_level, components] for top_level, components in modules_dict.items()]
180
+
181
+ # Calculate metadata
182
+ num_modules = len(modules_dict)
183
+ num_components = sum(len(components) for components in modules_dict.values())
184
+
185
+ # Get version
186
+ from importlib.metadata import version
187
+
188
+ langflow_version = version("langflow")
189
+
190
+ # Build index structure
191
+ index = {
192
+ "version": langflow_version,
193
+ "metadata": {
194
+ "num_modules": num_modules,
195
+ "num_components": num_components,
196
+ },
197
+ "entries": entries,
198
+ }
199
+
200
+ # Calculate hash
201
+ payload = orjson.dumps(index, option=orjson.OPT_SORT_KEYS)
202
+ index["sha256"] = hashlib.sha256(payload).hexdigest()
203
+
204
+ # Write to cache
205
+ json_bytes = orjson.dumps(index, option=orjson.OPT_SORT_KEYS | orjson.OPT_INDENT_2)
206
+ cache_path.write_bytes(json_bytes)
207
+
208
+ logger.debug(f"Saved generated component index to cache: {cache_path}")
209
+ except Exception as e: # noqa: BLE001
210
+ logger.debug(f"Failed to save generated index to cache: {e}")
211
+
212
+
213
+ async def _send_telemetry(
214
+ telemetry_service: Any,
215
+ index_source: str,
216
+ modules_dict: dict,
217
+ dev_mode: bool, # noqa: FBT001
218
+ target_modules: list[str] | None,
219
+ start_time_ms: int,
220
+ ) -> None:
221
+ """Send telemetry about component index loading.
222
+
223
+ Args:
224
+ telemetry_service: Telemetry service instance (optional)
225
+ index_source: Source of the index ("builtin", "cache", or "dynamic")
226
+ modules_dict: Dictionary of loaded components
227
+ dev_mode: Whether dev mode is enabled
228
+ target_modules: List of filtered modules if any
229
+ start_time_ms: Start time in milliseconds
230
+ """
231
+ if not telemetry_service:
232
+ return
233
+
234
+ try:
235
+ # Calculate metrics
236
+ num_modules = len(modules_dict)
237
+ num_components = sum(len(components) for components in modules_dict.values())
238
+ load_time_ms = int(time.time() * 1000) - start_time_ms
239
+ filtered_modules = ",".join(target_modules) if target_modules else None
240
+
241
+ # Import the payload class dynamically to avoid circular imports
242
+ from langflow.services.telemetry.schema import ComponentIndexPayload
243
+
244
+ payload = ComponentIndexPayload(
245
+ index_source=index_source,
246
+ num_modules=num_modules,
247
+ num_components=num_components,
248
+ dev_mode=dev_mode,
249
+ filtered_modules=filtered_modules,
250
+ load_time_ms=load_time_ms,
251
+ )
252
+
253
+ await telemetry_service.log_component_index(payload)
254
+ except Exception as e: # noqa: BLE001
255
+ # Don't fail component loading if telemetry fails
256
+ await logger.adebug(f"Failed to send component index telemetry: {e}")
257
+
258
+
259
+ async def _load_from_index_or_cache(
260
+ settings_service: Optional["SettingsService"] = None,
261
+ ) -> tuple[dict[str, Any], str | None]:
262
+ """Load components from prebuilt index or cache.
263
+
264
+ Args:
265
+ settings_service: Optional settings service to get custom index path
266
+
267
+ Returns:
268
+ Tuple of (modules_dict, index_source) where index_source is "builtin", "cache", or None if failed
269
+ """
270
+ modules_dict: dict[str, Any] = {}
271
+
272
+ # Try to load from prebuilt index first
273
+ custom_index_path = None
274
+ if settings_service and settings_service.settings.components_index_path:
275
+ custom_index_path = settings_service.settings.components_index_path
276
+ await logger.adebug(f"Using custom component index: {custom_index_path}")
277
+
278
+ index = _read_component_index(custom_index_path)
279
+ if index and "entries" in index:
280
+ source = custom_index_path or "built-in index"
281
+ await logger.adebug(f"Loading components from {source}")
282
+ # Reconstruct modules_dict from index entries
283
+ for top_level, components in index["entries"]:
284
+ if top_level not in modules_dict:
285
+ modules_dict[top_level] = {}
286
+ modules_dict[top_level].update(components)
287
+ await logger.adebug(f"Loaded {len(modules_dict)} component categories from index")
288
+ return modules_dict, "builtin"
289
+
290
+ # Index failed to load - try cache
291
+ await logger.adebug("Prebuilt index not available, checking cache")
292
+ try:
293
+ cache_path = _get_cache_path()
294
+ except Exception as e: # noqa: BLE001
295
+ await logger.adebug(f"Cache load failed: {e}")
296
+ else:
297
+ if cache_path.exists():
298
+ await logger.adebug(f"Attempting to load from cache: {cache_path}")
299
+ index = _read_component_index(str(cache_path))
300
+ if index and "entries" in index:
301
+ await logger.adebug("Loading components from cached index")
302
+ for top_level, components in index["entries"]:
303
+ if top_level not in modules_dict:
304
+ modules_dict[top_level] = {}
305
+ modules_dict[top_level].update(components)
306
+ await logger.adebug(f"Loaded {len(modules_dict)} component categories from cache")
307
+ return modules_dict, "cache"
308
+
309
+ return modules_dict, None
310
+
311
+
312
+ async def _load_components_dynamically(
313
+ target_modules: list[str] | None = None,
314
+ ) -> dict[str, Any]:
315
+ """Load components dynamically by scanning and importing modules.
316
+
317
+ Args:
318
+ target_modules: Optional list of specific module names to load (e.g., ["mistral", "openai"])
319
+
320
+ Returns:
321
+ Dictionary mapping top-level module names to their components
322
+ """
323
+ modules_dict: dict[str, Any] = {}
324
+
325
+ try:
326
+ import lfx.components as components_pkg
327
+ except ImportError as e:
328
+ await logger.aerror(f"Failed to import langflow.components package: {e}", exc_info=True)
329
+ return modules_dict
330
+
331
+ # Collect all module names to process
332
+ module_names = []
333
+ for _, modname, _ in pkgutil.walk_packages(components_pkg.__path__, prefix=components_pkg.__name__ + "."):
334
+ # Skip if the module is in the deactivated folder
335
+ if "deactivated" in modname:
336
+ continue
337
+
338
+ # If specific modules requested, filter by top-level module name
339
+ if target_modules:
340
+ # Extract top-level: "lfx.components.mistral.xyz" -> "mistral"
341
+ parts = modname.split(".")
342
+ if len(parts) > MIN_MODULE_PARTS and parts[2].lower() not in target_modules:
343
+ continue
344
+
345
+ module_names.append(modname)
346
+
347
+ if target_modules:
348
+ await logger.adebug(f"Found {len(module_names)} modules matching filter")
349
+
350
+ if not module_names:
351
+ return modules_dict
352
+
353
+ # Create tasks for parallel module processing
354
+ tasks = [asyncio.to_thread(_process_single_module, modname) for modname in module_names]
355
+
356
+ # Wait for all modules to be processed
357
+ try:
358
+ module_results = await asyncio.gather(*tasks, return_exceptions=True)
359
+ except Exception as e: # noqa: BLE001
360
+ await logger.aerror(f"Error during parallel module processing: {e}", exc_info=True)
361
+ return modules_dict
362
+
363
+ # Merge results from all modules
364
+ for result in module_results:
365
+ if isinstance(result, Exception):
366
+ await logger.awarning(f"Module processing failed: {result}")
367
+ continue
368
+
369
+ if result and isinstance(result, tuple) and len(result) == EXPECTED_RESULT_LENGTH:
370
+ top_level, components = result
371
+ if top_level and components:
372
+ if top_level not in modules_dict:
373
+ modules_dict[top_level] = {}
374
+ modules_dict[top_level].update(components)
375
+
376
+ return modules_dict
377
+
378
+
379
+ async def _load_full_dev_mode() -> tuple[dict[str, Any], str]:
380
+ """Load all components dynamically in full dev mode.
381
+
382
+ Returns:
383
+ Tuple of (modules_dict, index_source)
384
+ """
385
+ await logger.adebug("LFX_DEV full mode: loading all modules dynamically")
386
+ modules_dict = await _load_components_dynamically(target_modules=None)
387
+ return modules_dict, "dynamic"
388
+
389
+
390
+ async def _load_selective_dev_mode(
391
+ settings_service: Optional["SettingsService"],
392
+ target_modules: list[str],
393
+ ) -> tuple[dict[str, Any], str]:
394
+ """Load index and selectively reload specific modules.
395
+
396
+ Args:
397
+ settings_service: Settings service for custom index path
398
+ target_modules: List of module names to reload
399
+
400
+ Returns:
401
+ Tuple of (modules_dict, index_source)
402
+ """
403
+ await logger.adebug(f"LFX_DEV selective mode: reloading {target_modules}")
404
+ modules_dict, _ = await _load_from_index_or_cache(settings_service)
405
+
406
+ # Reload specific modules dynamically
407
+ dynamic_modules = await _load_components_dynamically(target_modules=target_modules)
408
+
409
+ # Merge/replace the targeted modules
410
+ for top_level, components in dynamic_modules.items():
411
+ if top_level not in modules_dict:
412
+ modules_dict[top_level] = {}
413
+ modules_dict[top_level].update(components)
414
+
415
+ await logger.adebug(f"Reloaded {len(target_modules)} module(s), kept others from index")
416
+ return modules_dict, "dynamic"
417
+
418
+
419
+ async def _load_production_mode(
420
+ settings_service: Optional["SettingsService"],
421
+ ) -> tuple[dict[str, Any], str]:
422
+ """Load components in production mode with fallback chain.
423
+
424
+ Tries: index -> cache -> dynamic build (with caching)
425
+
426
+ Args:
427
+ settings_service: Settings service for custom index path
428
+
429
+ Returns:
430
+ Tuple of (modules_dict, index_source)
431
+ """
432
+ modules_dict, index_source = await _load_from_index_or_cache(settings_service)
433
+
434
+ if not index_source:
435
+ # No index or cache available - build dynamically and save
436
+ await logger.adebug("Falling back to dynamic loading")
437
+ modules_dict = await _load_components_dynamically(target_modules=None)
438
+ index_source = "dynamic"
439
+
440
+ # Save to cache for future use
441
+ if modules_dict:
442
+ await logger.adebug("Saving generated component index to cache")
443
+ _save_generated_index(modules_dict)
444
+
445
+ return modules_dict, index_source
446
+
447
+
448
+ async def import_langflow_components(
449
+ settings_service: Optional["SettingsService"] = None,
450
+ telemetry_service: Any | None = None,
451
+ ) -> dict[str, dict[str, Any]]:
452
+ """Asynchronously discovers and loads all built-in Langflow components.
453
+
454
+ Loading Strategy:
455
+ - Production mode: Load from prebuilt index -> cache -> build dynamically (with caching)
456
+ - Dev mode (full): Build all components dynamically
457
+ - Dev mode (selective): Load index + replace specific modules dynamically
458
+
459
+ Args:
460
+ settings_service: Optional settings service to get custom index path
461
+ telemetry_service: Optional telemetry service to log component loading metrics
462
+
463
+ Returns:
464
+ A dictionary with a "components" key mapping top-level package names to their component templates.
465
+ """
466
+ start_time_ms: int = int(time.time() * 1000)
467
+ dev_mode_enabled, target_modules = _parse_dev_mode()
468
+
469
+ # Strategy pattern: map dev mode state to loading function
470
+ if dev_mode_enabled and not target_modules:
471
+ modules_dict, index_source = await _load_full_dev_mode()
472
+ elif dev_mode_enabled and target_modules:
473
+ modules_dict, index_source = await _load_selective_dev_mode(settings_service, target_modules)
474
+ else:
475
+ modules_dict, index_source = await _load_production_mode(settings_service)
476
+
477
+ # Send telemetry
478
+ await _send_telemetry(
479
+ telemetry_service, index_source, modules_dict, dev_mode_enabled, target_modules, start_time_ms
480
+ )
481
+
482
+ return {"components": modules_dict}
483
+
484
+
485
+ def _process_single_module(modname: str) -> tuple[str, dict] | None:
486
+ """Process a single module and return its components.
487
+
488
+ Args:
489
+ modname: The full module name to process
490
+
491
+ Returns:
492
+ A tuple of (top_level_package, components_dict) or None if processing failed
493
+ """
494
+ try:
495
+ module = importlib.import_module(modname)
496
+ except Exception as e: # noqa: BLE001
497
+ # Catch all exceptions during import to prevent component failures from crashing startup
498
+ # TODO: Surface these errors to the UI in a friendly manner
499
+ logger.error(f"Failed to import module {modname}: {e}", exc_info=True)
500
+ return None
501
+ # Extract the top-level subpackage name after "lfx.components."
502
+ # e.g., "lfx.components.Notion.add_content_to_page" -> "Notion"
503
+ mod_parts = modname.split(".")
504
+ if len(mod_parts) <= MIN_MODULE_PARTS:
505
+ return None
506
+
507
+ top_level = mod_parts[2]
508
+ module_components = {}
509
+
510
+ # Bind frequently used functions for small speed gain
511
+ _getattr = getattr
512
+
513
+ # Fast path: only check class objects defined in this module
514
+ failed_count = []
515
+ for name, obj in vars(module).items():
516
+ if not isinstance(obj, type):
517
+ continue
518
+
519
+ # Only consider classes defined in this module
520
+ if obj.__module__ != modname:
521
+ continue
522
+
523
+ # Check for required attributes
524
+ if not (
525
+ _getattr(obj, "code_class_base_inheritance", None) is not None
526
+ or _getattr(obj, "_code_class_base_inheritance", None) is not None
527
+ ):
528
+ continue
529
+
530
+ try:
531
+ comp_instance = obj()
532
+ # modname is the full module name without the name of the obj
533
+ full_module_name = f"{modname}.{name}"
534
+ comp_template, _ = create_component_template(
535
+ component_extractor=comp_instance, module_name=full_module_name
536
+ )
537
+ component_name = obj.name if hasattr(obj, "name") and obj.name else name
538
+ module_components[component_name] = comp_template
539
+ except Exception as e: # noqa: BLE001
540
+ failed_count.append(f"{name}: {e}")
541
+ continue
542
+
543
+ if failed_count:
544
+ logger.warning(
545
+ f"Skipped {len(failed_count)} component class{'es' if len(failed_count) != 1 else ''} "
546
+ f"in module '{modname}' due to instantiation failure: {', '.join(failed_count)}"
547
+ )
548
+ logger.debug(f"Processed module {modname}")
549
+ return (top_level, module_components)
550
+
551
+
552
+ async def _determine_loading_strategy(settings_service: "SettingsService") -> dict:
553
+ """Determines and executes the appropriate component loading strategy.
554
+
555
+ Args:
556
+ settings_service: Service containing loading configuration
557
+
558
+ Returns:
559
+ Dictionary containing loaded component types and templates
560
+ """
561
+ component_cache.all_types_dict = {}
562
+ if settings_service.settings.lazy_load_components:
563
+ # Partial loading mode - just load component metadata
564
+ await logger.adebug("Using partial component loading")
565
+ component_cache.all_types_dict = await aget_component_metadata(settings_service.settings.components_path)
566
+ elif settings_service.settings.components_path:
567
+ # Traditional full loading - filter out base components path to only load custom components
568
+ custom_paths = [p for p in settings_service.settings.components_path if p != BASE_COMPONENTS_PATH]
569
+ if custom_paths:
570
+ component_cache.all_types_dict = await aget_all_types_dict(custom_paths)
571
+
572
+ # Log custom component loading stats
573
+ components_dict = component_cache.all_types_dict or {}
574
+ component_count = sum(len(comps) for comps in components_dict.get("components", {}).values())
575
+ if component_count > 0 and settings_service.settings.components_path:
576
+ await logger.adebug(
577
+ f"Built {component_count} custom components from {settings_service.settings.components_path}"
578
+ )
579
+
580
+ return component_cache.all_types_dict
581
+
582
+
583
+ async def get_and_cache_all_types_dict(
584
+ settings_service: "SettingsService",
585
+ telemetry_service: Any | None = None,
586
+ ):
587
+ """Retrieves and caches the complete dictionary of component types and templates.
588
+
589
+ Supports both full and partial (lazy) loading. If the cache is empty, loads built-in Langflow
590
+ components and either fully loads all components or loads only their metadata, depending on the
591
+ lazy loading setting. Merges built-in and custom components into the cache and returns the
592
+ resulting dictionary.
593
+
594
+ Args:
595
+ settings_service: Settings service instance
596
+ telemetry_service: Optional telemetry service for tracking component loading metrics
597
+ """
598
+ if component_cache.all_types_dict is None:
599
+ await logger.adebug("Building components cache")
600
+
601
+ langflow_components = await import_langflow_components(settings_service, telemetry_service)
602
+ custom_components_dict = await _determine_loading_strategy(settings_service)
603
+
604
+ # Flatten custom dict if it has a "components" wrapper
605
+ custom_flat = custom_components_dict.get("components", custom_components_dict) or {}
606
+
607
+ # Merge built-in and custom components (no wrapper at cache level)
608
+ component_cache.all_types_dict = {
609
+ **langflow_components["components"],
610
+ **custom_flat,
611
+ }
612
+ component_count = sum(len(comps) for comps in component_cache.all_types_dict.values())
613
+ await logger.adebug(f"Loaded {component_count} components")
614
+ return component_cache.all_types_dict
615
+
616
+
617
+ async def aget_all_types_dict(components_paths: list[str]):
618
+ """Get all types dictionary with full component loading."""
619
+ return await abuild_custom_components(components_paths=components_paths)
620
+
621
+
622
+ async def aget_component_metadata(components_paths: list[str]):
623
+ """Asynchronously retrieves minimal metadata for all components in the specified paths.
624
+
625
+ Builds a dictionary containing basic information (such as display name, type, and description) for
626
+ each discovered component, without loading their full templates. Each component entry is marked as
627
+ `lazy_loaded` to indicate that only metadata has been loaded.
628
+
629
+ Args:
630
+ components_paths: List of filesystem paths to search for component types and names.
631
+
632
+ Returns:
633
+ A dictionary with component types as keys and their corresponding component metadata as values.
634
+ """
635
+ # This builds a skeleton of the all_types_dict with just basic component info
636
+
637
+ components_dict: dict = {"components": {}}
638
+
639
+ if not components_paths:
640
+ return components_dict
641
+
642
+ # Get all component types
643
+ component_types = await discover_component_types(components_paths)
644
+ await logger.adebug(f"Discovered {len(component_types)} component types: {', '.join(component_types)}")
645
+
646
+ # For each component type directory
647
+ for component_type in component_types:
648
+ components_dict["components"][component_type] = {}
649
+
650
+ # Get list of components in this type
651
+ component_names = await discover_component_names(component_type, components_paths)
652
+ await logger.adebug(f"Found {len(component_names)} components for type {component_type}")
653
+
654
+ # Create stub entries with just basic metadata
655
+ for name in component_names:
656
+ # Get minimal metadata for component
657
+ metadata = await get_component_minimal_metadata(component_type, name, components_paths)
658
+
659
+ if metadata:
660
+ components_dict["components"][component_type][name] = metadata
661
+ # Mark as needing full loading
662
+ components_dict["components"][component_type][name]["lazy_loaded"] = True
663
+
664
+ return components_dict
665
+
666
+
667
+ async def discover_component_types(components_paths: list[str]) -> list[str]:
668
+ """Discover available component types by scanning directories."""
669
+ component_types: set[str] = set()
670
+
671
+ for path in components_paths:
672
+ path_obj = Path(path)
673
+ if not path_obj.exists():
674
+ continue
675
+
676
+ for item in path_obj.iterdir():
677
+ # Only include directories that don't start with _ or .
678
+ if item.is_dir() and not item.name.startswith(("_", ".")):
679
+ component_types.add(item.name)
680
+
681
+ # Add known types that might not be in directories
682
+ standard_types = {
683
+ "agents",
684
+ "chains",
685
+ "embeddings",
686
+ "llms",
687
+ "memories",
688
+ "prompts",
689
+ "tools",
690
+ "retrievers",
691
+ "textsplitters",
692
+ "toolkits",
693
+ "utilities",
694
+ "vectorstores",
695
+ "custom_components",
696
+ "documentloaders",
697
+ "outputparsers",
698
+ "wrappers",
699
+ }
700
+
701
+ component_types.update(standard_types)
702
+
703
+ return sorted(component_types)
704
+
705
+
706
+ async def discover_component_names(component_type: str, components_paths: list[str]) -> list[str]:
707
+ """Discover component names for a specific type by scanning directories."""
708
+ component_names: set[str] = set()
709
+
710
+ for path in components_paths:
711
+ type_dir = Path(path) / component_type
712
+
713
+ if type_dir.exists():
714
+ for filename in type_dir.iterdir():
715
+ # Get Python files that don't start with __
716
+ if filename.name.endswith(".py") and not filename.name.startswith("__"):
717
+ component_name = filename.name[:-3] # Remove .py extension
718
+ component_names.add(component_name)
719
+
720
+ return sorted(component_names)
721
+
722
+
723
+ async def get_component_minimal_metadata(component_type: str, component_name: str, components_paths: list[str]):
724
+ """Extract minimal metadata for a component without loading its full implementation."""
725
+ # Create a more complete metadata structure that the UI needs
726
+ metadata = {
727
+ "display_name": component_name.replace("_", " ").title(),
728
+ "name": component_name,
729
+ "type": component_type,
730
+ "description": f"A {component_type} component (not fully loaded)",
731
+ "template": {
732
+ "_type": component_type,
733
+ "inputs": {},
734
+ "outputs": {},
735
+ "output_types": [],
736
+ "documentation": f"A {component_type} component",
737
+ "display_name": component_name.replace("_", " ").title(),
738
+ "base_classes": [component_type],
739
+ },
740
+ }
741
+
742
+ # Try to find the file to verify it exists
743
+ component_path = None
744
+ for path in components_paths:
745
+ candidate_path = Path(path) / component_type / f"{component_name}.py"
746
+ if candidate_path.exists():
747
+ component_path = candidate_path
748
+ break
749
+
750
+ if not component_path:
751
+ return None
752
+
753
+ return metadata
754
+
755
+
756
+ async def ensure_component_loaded(component_type: str, component_name: str, settings_service: "SettingsService"):
757
+ """Ensure a component is fully loaded if it was only partially loaded."""
758
+ # If already fully loaded, return immediately
759
+ component_key = f"{component_type}:{component_name}"
760
+ if component_key in component_cache.fully_loaded_components:
761
+ return
762
+
763
+ # If we don't have a cache or the component doesn't exist in the cache, nothing to do
764
+ if (
765
+ not component_cache.all_types_dict
766
+ or "components" not in component_cache.all_types_dict
767
+ or component_type not in component_cache.all_types_dict["components"]
768
+ or component_name not in component_cache.all_types_dict["components"][component_type]
769
+ ):
770
+ return
771
+
772
+ # Check if component is marked for lazy loading
773
+ if component_cache.all_types_dict["components"][component_type][component_name].get("lazy_loaded", False):
774
+ await logger.adebug(f"Fully loading component {component_type}:{component_name}")
775
+
776
+ # Load just this specific component
777
+ full_component = await load_single_component(
778
+ component_type, component_name, settings_service.settings.components_path
779
+ )
780
+
781
+ if full_component:
782
+ # Replace the stub with the fully loaded component
783
+ component_cache.all_types_dict["components"][component_type][component_name] = full_component
784
+ # Remove lazy_loaded flag if it exists
785
+ if "lazy_loaded" in component_cache.all_types_dict["components"][component_type][component_name]:
786
+ del component_cache.all_types_dict["components"][component_type][component_name]["lazy_loaded"]
787
+
788
+ # Mark as fully loaded
789
+ component_cache.fully_loaded_components[component_key] = True
790
+ await logger.adebug(f"Component {component_type}:{component_name} fully loaded")
791
+ else:
792
+ await logger.awarning(f"Failed to fully load component {component_type}:{component_name}")
793
+
794
+
795
+ async def load_single_component(component_type: str, component_name: str, components_paths: list[str]):
796
+ """Load a single component fully."""
797
+ from lfx.custom.utils import get_single_component_dict
798
+
799
+ try:
800
+ # Delegate to a more specific function that knows how to load
801
+ # a single component of a specific type
802
+ return await get_single_component_dict(component_type, component_name, components_paths)
803
+ except (ImportError, ModuleNotFoundError) as e:
804
+ # Handle issues with importing the component or its dependencies
805
+ await logger.aerror(f"Import error loading component {component_type}:{component_name}: {e!s}")
806
+ return None
807
+ except (AttributeError, TypeError) as e:
808
+ # Handle issues with component structure or type errors
809
+ await logger.aerror(f"Component structure error for {component_type}:{component_name}: {e!s}")
810
+ return None
811
+ except FileNotFoundError as e:
812
+ # Handle missing files
813
+ await logger.aerror(f"File not found for component {component_type}:{component_name}: {e!s}")
814
+ return None
815
+ except ValueError as e:
816
+ # Handle invalid values or configurations
817
+ await logger.aerror(f"Invalid configuration for component {component_type}:{component_name}: {e!s}")
818
+ return None
819
+ except (KeyError, IndexError) as e:
820
+ # Handle data structure access errors
821
+ await logger.aerror(f"Data structure error for component {component_type}:{component_name}: {e!s}")
822
+ return None
823
+ except RuntimeError as e:
824
+ # Handle runtime errors
825
+ await logger.aerror(f"Runtime error loading component {component_type}:{component_name}: {e!s}")
826
+ await logger.adebug("Full traceback for runtime error", exc_info=True)
827
+ return None
828
+ except OSError as e:
829
+ # Handle OS-related errors (file system, permissions, etc.)
830
+ await logger.aerror(f"OS error loading component {component_type}:{component_name}: {e!s}")
831
+ return None
832
+
833
+
834
+ # Also add a utility function to load specific component types
835
+ async def get_type_dict(component_type: str, settings_service: Optional["SettingsService"] = None):
836
+ """Get a specific component type dictionary, loading if needed."""
837
+ if settings_service is None:
838
+ # Import here to avoid circular imports
839
+ from langflow.services.deps import get_settings_service
840
+
841
+ settings_service = get_settings_service()
842
+
843
+ # Make sure all_types_dict is loaded (at least partially)
844
+ if component_cache.all_types_dict is None:
845
+ await get_and_cache_all_types_dict(settings_service)
846
+
847
+ # Check if component type exists in the cache
848
+ if (
849
+ component_cache.all_types_dict
850
+ and "components" in component_cache.all_types_dict
851
+ and component_type in component_cache.all_types_dict["components"]
852
+ ):
853
+ # If in lazy mode, ensure all components of this type are fully loaded
854
+ if settings_service.settings.lazy_load_components:
855
+ for component_name in list(component_cache.all_types_dict["components"][component_type].keys()):
856
+ await ensure_component_loaded(component_type, component_name, settings_service)
857
+
858
+ return component_cache.all_types_dict["components"][component_type]
859
+
860
+ return {}
861
+
862
+
863
+ # TypeError: unhashable type: 'list'
864
+ def key_func(*args, **kwargs):
865
+ # components_paths is a list of paths
866
+ return json.dumps(args) + json.dumps(kwargs)
867
+
868
+
869
+ async def aget_all_components(components_paths, *, as_dict=False):
870
+ """Get all components names combining native and custom components."""
871
+ all_types_dict = await aget_all_types_dict(components_paths)
872
+ components = {} if as_dict else []
873
+ for category in all_types_dict.values():
874
+ for component in category.values():
875
+ component["name"] = component["display_name"]
876
+ if as_dict:
877
+ components[component["name"]] = component
878
+ else:
879
+ components.append(component)
880
+ return components
881
+
882
+
883
+ def get_all_components(components_paths, *, as_dict=False):
884
+ """Get all components names combining native and custom components."""
885
+ # Import here to avoid circular imports
886
+ from lfx.custom.utils import build_custom_components
887
+
888
+ all_types_dict = build_custom_components(components_paths=components_paths)
889
+ components = [] if not as_dict else {}
890
+ for category in all_types_dict.values():
891
+ for component in category.values():
892
+ component["name"] = component["display_name"]
893
+ if as_dict:
894
+ components[component["name"]] = component
895
+ else:
896
+ components.append(component)
897
+ return components