lfx-nightly 0.1.11.dev0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (699) hide show
  1. lfx/__init__.py +0 -0
  2. lfx/__main__.py +25 -0
  3. lfx/base/__init__.py +0 -0
  4. lfx/base/agents/__init__.py +0 -0
  5. lfx/base/agents/agent.py +268 -0
  6. lfx/base/agents/callback.py +130 -0
  7. lfx/base/agents/context.py +109 -0
  8. lfx/base/agents/crewai/__init__.py +0 -0
  9. lfx/base/agents/crewai/crew.py +231 -0
  10. lfx/base/agents/crewai/tasks.py +12 -0
  11. lfx/base/agents/default_prompts.py +23 -0
  12. lfx/base/agents/errors.py +15 -0
  13. lfx/base/agents/events.py +346 -0
  14. lfx/base/agents/utils.py +205 -0
  15. lfx/base/astra_assistants/__init__.py +0 -0
  16. lfx/base/astra_assistants/util.py +171 -0
  17. lfx/base/chains/__init__.py +0 -0
  18. lfx/base/chains/model.py +19 -0
  19. lfx/base/composio/__init__.py +0 -0
  20. lfx/base/composio/composio_base.py +1291 -0
  21. lfx/base/compressors/__init__.py +0 -0
  22. lfx/base/compressors/model.py +60 -0
  23. lfx/base/constants.py +46 -0
  24. lfx/base/curl/__init__.py +0 -0
  25. lfx/base/curl/parse.py +188 -0
  26. lfx/base/data/__init__.py +5 -0
  27. lfx/base/data/base_file.py +685 -0
  28. lfx/base/data/docling_utils.py +245 -0
  29. lfx/base/data/utils.py +198 -0
  30. lfx/base/document_transformers/__init__.py +0 -0
  31. lfx/base/document_transformers/model.py +43 -0
  32. lfx/base/embeddings/__init__.py +0 -0
  33. lfx/base/embeddings/aiml_embeddings.py +62 -0
  34. lfx/base/embeddings/model.py +26 -0
  35. lfx/base/flow_processing/__init__.py +0 -0
  36. lfx/base/flow_processing/utils.py +86 -0
  37. lfx/base/huggingface/__init__.py +0 -0
  38. lfx/base/huggingface/model_bridge.py +133 -0
  39. lfx/base/io/__init__.py +0 -0
  40. lfx/base/io/chat.py +20 -0
  41. lfx/base/io/text.py +22 -0
  42. lfx/base/langchain_utilities/__init__.py +0 -0
  43. lfx/base/langchain_utilities/model.py +35 -0
  44. lfx/base/langchain_utilities/spider_constants.py +1 -0
  45. lfx/base/langwatch/__init__.py +0 -0
  46. lfx/base/langwatch/utils.py +18 -0
  47. lfx/base/mcp/__init__.py +0 -0
  48. lfx/base/mcp/constants.py +2 -0
  49. lfx/base/mcp/util.py +1398 -0
  50. lfx/base/memory/__init__.py +0 -0
  51. lfx/base/memory/memory.py +49 -0
  52. lfx/base/memory/model.py +38 -0
  53. lfx/base/models/__init__.py +3 -0
  54. lfx/base/models/aiml_constants.py +51 -0
  55. lfx/base/models/anthropic_constants.py +47 -0
  56. lfx/base/models/aws_constants.py +151 -0
  57. lfx/base/models/chat_result.py +76 -0
  58. lfx/base/models/google_generative_ai_constants.py +70 -0
  59. lfx/base/models/groq_constants.py +134 -0
  60. lfx/base/models/model.py +375 -0
  61. lfx/base/models/model_input_constants.py +307 -0
  62. lfx/base/models/model_metadata.py +41 -0
  63. lfx/base/models/model_utils.py +8 -0
  64. lfx/base/models/novita_constants.py +35 -0
  65. lfx/base/models/ollama_constants.py +49 -0
  66. lfx/base/models/openai_constants.py +122 -0
  67. lfx/base/models/sambanova_constants.py +18 -0
  68. lfx/base/processing/__init__.py +0 -0
  69. lfx/base/prompts/__init__.py +0 -0
  70. lfx/base/prompts/api_utils.py +224 -0
  71. lfx/base/prompts/utils.py +61 -0
  72. lfx/base/textsplitters/__init__.py +0 -0
  73. lfx/base/textsplitters/model.py +28 -0
  74. lfx/base/tools/__init__.py +0 -0
  75. lfx/base/tools/base.py +26 -0
  76. lfx/base/tools/component_tool.py +325 -0
  77. lfx/base/tools/constants.py +49 -0
  78. lfx/base/tools/flow_tool.py +132 -0
  79. lfx/base/tools/run_flow.py +224 -0
  80. lfx/base/vectorstores/__init__.py +0 -0
  81. lfx/base/vectorstores/model.py +193 -0
  82. lfx/base/vectorstores/utils.py +22 -0
  83. lfx/base/vectorstores/vector_store_connection_decorator.py +52 -0
  84. lfx/cli/__init__.py +5 -0
  85. lfx/cli/commands.py +319 -0
  86. lfx/cli/common.py +650 -0
  87. lfx/cli/run.py +441 -0
  88. lfx/cli/script_loader.py +247 -0
  89. lfx/cli/serve_app.py +546 -0
  90. lfx/cli/validation.py +69 -0
  91. lfx/components/FAISS/__init__.py +34 -0
  92. lfx/components/FAISS/faiss.py +111 -0
  93. lfx/components/Notion/__init__.py +19 -0
  94. lfx/components/Notion/add_content_to_page.py +269 -0
  95. lfx/components/Notion/create_page.py +94 -0
  96. lfx/components/Notion/list_database_properties.py +68 -0
  97. lfx/components/Notion/list_pages.py +122 -0
  98. lfx/components/Notion/list_users.py +77 -0
  99. lfx/components/Notion/page_content_viewer.py +93 -0
  100. lfx/components/Notion/search.py +111 -0
  101. lfx/components/Notion/update_page_property.py +114 -0
  102. lfx/components/__init__.py +411 -0
  103. lfx/components/_importing.py +42 -0
  104. lfx/components/agentql/__init__.py +3 -0
  105. lfx/components/agentql/agentql_api.py +151 -0
  106. lfx/components/agents/__init__.py +34 -0
  107. lfx/components/agents/agent.py +558 -0
  108. lfx/components/agents/mcp_component.py +501 -0
  109. lfx/components/aiml/__init__.py +37 -0
  110. lfx/components/aiml/aiml.py +112 -0
  111. lfx/components/aiml/aiml_embeddings.py +37 -0
  112. lfx/components/amazon/__init__.py +36 -0
  113. lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
  114. lfx/components/amazon/amazon_bedrock_model.py +124 -0
  115. lfx/components/amazon/s3_bucket_uploader.py +211 -0
  116. lfx/components/anthropic/__init__.py +34 -0
  117. lfx/components/anthropic/anthropic.py +187 -0
  118. lfx/components/apify/__init__.py +5 -0
  119. lfx/components/apify/apify_actor.py +325 -0
  120. lfx/components/arxiv/__init__.py +3 -0
  121. lfx/components/arxiv/arxiv.py +163 -0
  122. lfx/components/assemblyai/__init__.py +46 -0
  123. lfx/components/assemblyai/assemblyai_get_subtitles.py +83 -0
  124. lfx/components/assemblyai/assemblyai_lemur.py +183 -0
  125. lfx/components/assemblyai/assemblyai_list_transcripts.py +95 -0
  126. lfx/components/assemblyai/assemblyai_poll_transcript.py +72 -0
  127. lfx/components/assemblyai/assemblyai_start_transcript.py +188 -0
  128. lfx/components/azure/__init__.py +37 -0
  129. lfx/components/azure/azure_openai.py +95 -0
  130. lfx/components/azure/azure_openai_embeddings.py +83 -0
  131. lfx/components/baidu/__init__.py +32 -0
  132. lfx/components/baidu/baidu_qianfan_chat.py +113 -0
  133. lfx/components/bing/__init__.py +3 -0
  134. lfx/components/bing/bing_search_api.py +61 -0
  135. lfx/components/cassandra/__init__.py +40 -0
  136. lfx/components/cassandra/cassandra.py +264 -0
  137. lfx/components/cassandra/cassandra_chat.py +92 -0
  138. lfx/components/cassandra/cassandra_graph.py +238 -0
  139. lfx/components/chains/__init__.py +3 -0
  140. lfx/components/chroma/__init__.py +34 -0
  141. lfx/components/chroma/chroma.py +167 -0
  142. lfx/components/cleanlab/__init__.py +40 -0
  143. lfx/components/cleanlab/cleanlab_evaluator.py +155 -0
  144. lfx/components/cleanlab/cleanlab_rag_evaluator.py +254 -0
  145. lfx/components/cleanlab/cleanlab_remediator.py +131 -0
  146. lfx/components/clickhouse/__init__.py +34 -0
  147. lfx/components/clickhouse/clickhouse.py +135 -0
  148. lfx/components/cloudflare/__init__.py +32 -0
  149. lfx/components/cloudflare/cloudflare.py +81 -0
  150. lfx/components/cohere/__init__.py +40 -0
  151. lfx/components/cohere/cohere_embeddings.py +81 -0
  152. lfx/components/cohere/cohere_models.py +46 -0
  153. lfx/components/cohere/cohere_rerank.py +51 -0
  154. lfx/components/composio/__init__.py +74 -0
  155. lfx/components/composio/composio_api.py +268 -0
  156. lfx/components/composio/dropbox_compnent.py +11 -0
  157. lfx/components/composio/github_composio.py +11 -0
  158. lfx/components/composio/gmail_composio.py +38 -0
  159. lfx/components/composio/googlecalendar_composio.py +11 -0
  160. lfx/components/composio/googlemeet_composio.py +11 -0
  161. lfx/components/composio/googletasks_composio.py +8 -0
  162. lfx/components/composio/linear_composio.py +11 -0
  163. lfx/components/composio/outlook_composio.py +11 -0
  164. lfx/components/composio/reddit_composio.py +11 -0
  165. lfx/components/composio/slack_composio.py +582 -0
  166. lfx/components/composio/slackbot_composio.py +11 -0
  167. lfx/components/composio/supabase_composio.py +11 -0
  168. lfx/components/composio/todoist_composio.py +11 -0
  169. lfx/components/composio/youtube_composio.py +11 -0
  170. lfx/components/confluence/__init__.py +3 -0
  171. lfx/components/confluence/confluence.py +84 -0
  172. lfx/components/couchbase/__init__.py +34 -0
  173. lfx/components/couchbase/couchbase.py +102 -0
  174. lfx/components/crewai/__init__.py +49 -0
  175. lfx/components/crewai/crewai.py +107 -0
  176. lfx/components/crewai/hierarchical_crew.py +46 -0
  177. lfx/components/crewai/hierarchical_task.py +44 -0
  178. lfx/components/crewai/sequential_crew.py +52 -0
  179. lfx/components/crewai/sequential_task.py +73 -0
  180. lfx/components/crewai/sequential_task_agent.py +143 -0
  181. lfx/components/custom_component/__init__.py +34 -0
  182. lfx/components/custom_component/custom_component.py +31 -0
  183. lfx/components/data/__init__.py +64 -0
  184. lfx/components/data/api_request.py +544 -0
  185. lfx/components/data/csv_to_data.py +95 -0
  186. lfx/components/data/directory.py +113 -0
  187. lfx/components/data/file.py +577 -0
  188. lfx/components/data/json_to_data.py +98 -0
  189. lfx/components/data/news_search.py +164 -0
  190. lfx/components/data/rss.py +69 -0
  191. lfx/components/data/sql_executor.py +101 -0
  192. lfx/components/data/url.py +311 -0
  193. lfx/components/data/web_search.py +112 -0
  194. lfx/components/data/webhook.py +56 -0
  195. lfx/components/datastax/__init__.py +70 -0
  196. lfx/components/datastax/astra_assistant_manager.py +306 -0
  197. lfx/components/datastax/astra_db.py +75 -0
  198. lfx/components/datastax/astra_vectorize.py +124 -0
  199. lfx/components/datastax/astradb.py +1285 -0
  200. lfx/components/datastax/astradb_cql.py +314 -0
  201. lfx/components/datastax/astradb_graph.py +330 -0
  202. lfx/components/datastax/astradb_tool.py +414 -0
  203. lfx/components/datastax/astradb_vectorstore.py +1285 -0
  204. lfx/components/datastax/cassandra.py +92 -0
  205. lfx/components/datastax/create_assistant.py +58 -0
  206. lfx/components/datastax/create_thread.py +32 -0
  207. lfx/components/datastax/dotenv.py +35 -0
  208. lfx/components/datastax/get_assistant.py +37 -0
  209. lfx/components/datastax/getenvvar.py +30 -0
  210. lfx/components/datastax/graph_rag.py +141 -0
  211. lfx/components/datastax/hcd.py +314 -0
  212. lfx/components/datastax/list_assistants.py +25 -0
  213. lfx/components/datastax/run.py +89 -0
  214. lfx/components/deactivated/__init__.py +15 -0
  215. lfx/components/deactivated/amazon_kendra.py +66 -0
  216. lfx/components/deactivated/chat_litellm_model.py +158 -0
  217. lfx/components/deactivated/code_block_extractor.py +26 -0
  218. lfx/components/deactivated/documents_to_data.py +22 -0
  219. lfx/components/deactivated/embed.py +16 -0
  220. lfx/components/deactivated/extract_key_from_data.py +46 -0
  221. lfx/components/deactivated/json_document_builder.py +57 -0
  222. lfx/components/deactivated/list_flows.py +20 -0
  223. lfx/components/deactivated/mcp_sse.py +61 -0
  224. lfx/components/deactivated/mcp_stdio.py +62 -0
  225. lfx/components/deactivated/merge_data.py +93 -0
  226. lfx/components/deactivated/message.py +37 -0
  227. lfx/components/deactivated/metal.py +54 -0
  228. lfx/components/deactivated/multi_query.py +59 -0
  229. lfx/components/deactivated/retriever.py +43 -0
  230. lfx/components/deactivated/selective_passthrough.py +77 -0
  231. lfx/components/deactivated/should_run_next.py +40 -0
  232. lfx/components/deactivated/split_text.py +63 -0
  233. lfx/components/deactivated/store_message.py +24 -0
  234. lfx/components/deactivated/sub_flow.py +124 -0
  235. lfx/components/deactivated/vectara_self_query.py +76 -0
  236. lfx/components/deactivated/vector_store.py +24 -0
  237. lfx/components/deepseek/__init__.py +34 -0
  238. lfx/components/deepseek/deepseek.py +136 -0
  239. lfx/components/docling/__init__.py +43 -0
  240. lfx/components/docling/chunk_docling_document.py +186 -0
  241. lfx/components/docling/docling_inline.py +231 -0
  242. lfx/components/docling/docling_remote.py +193 -0
  243. lfx/components/docling/export_docling_document.py +117 -0
  244. lfx/components/documentloaders/__init__.py +3 -0
  245. lfx/components/duckduckgo/__init__.py +3 -0
  246. lfx/components/duckduckgo/duck_duck_go_search_run.py +92 -0
  247. lfx/components/elastic/__init__.py +37 -0
  248. lfx/components/elastic/elasticsearch.py +267 -0
  249. lfx/components/elastic/opensearch.py +243 -0
  250. lfx/components/embeddings/__init__.py +37 -0
  251. lfx/components/embeddings/similarity.py +76 -0
  252. lfx/components/embeddings/text_embedder.py +64 -0
  253. lfx/components/exa/__init__.py +3 -0
  254. lfx/components/exa/exa_search.py +68 -0
  255. lfx/components/firecrawl/__init__.py +43 -0
  256. lfx/components/firecrawl/firecrawl_crawl_api.py +88 -0
  257. lfx/components/firecrawl/firecrawl_extract_api.py +136 -0
  258. lfx/components/firecrawl/firecrawl_map_api.py +89 -0
  259. lfx/components/firecrawl/firecrawl_scrape_api.py +73 -0
  260. lfx/components/git/__init__.py +4 -0
  261. lfx/components/git/git.py +262 -0
  262. lfx/components/git/gitextractor.py +196 -0
  263. lfx/components/glean/__init__.py +3 -0
  264. lfx/components/glean/glean_search_api.py +173 -0
  265. lfx/components/google/__init__.py +17 -0
  266. lfx/components/google/gmail.py +192 -0
  267. lfx/components/google/google_bq_sql_executor.py +157 -0
  268. lfx/components/google/google_drive.py +92 -0
  269. lfx/components/google/google_drive_search.py +152 -0
  270. lfx/components/google/google_generative_ai.py +147 -0
  271. lfx/components/google/google_generative_ai_embeddings.py +141 -0
  272. lfx/components/google/google_oauth_token.py +89 -0
  273. lfx/components/google/google_search_api_core.py +68 -0
  274. lfx/components/google/google_serper_api_core.py +74 -0
  275. lfx/components/groq/__init__.py +34 -0
  276. lfx/components/groq/groq.py +136 -0
  277. lfx/components/helpers/__init__.py +52 -0
  278. lfx/components/helpers/calculator_core.py +89 -0
  279. lfx/components/helpers/create_list.py +40 -0
  280. lfx/components/helpers/current_date.py +42 -0
  281. lfx/components/helpers/id_generator.py +42 -0
  282. lfx/components/helpers/memory.py +251 -0
  283. lfx/components/helpers/output_parser.py +45 -0
  284. lfx/components/helpers/store_message.py +90 -0
  285. lfx/components/homeassistant/__init__.py +7 -0
  286. lfx/components/homeassistant/home_assistant_control.py +152 -0
  287. lfx/components/homeassistant/list_home_assistant_states.py +137 -0
  288. lfx/components/huggingface/__init__.py +37 -0
  289. lfx/components/huggingface/huggingface.py +197 -0
  290. lfx/components/huggingface/huggingface_inference_api.py +106 -0
  291. lfx/components/ibm/__init__.py +34 -0
  292. lfx/components/ibm/watsonx.py +203 -0
  293. lfx/components/ibm/watsonx_embeddings.py +135 -0
  294. lfx/components/icosacomputing/__init__.py +5 -0
  295. lfx/components/icosacomputing/combinatorial_reasoner.py +84 -0
  296. lfx/components/input_output/__init__.py +38 -0
  297. lfx/components/input_output/chat.py +120 -0
  298. lfx/components/input_output/chat_output.py +200 -0
  299. lfx/components/input_output/text.py +27 -0
  300. lfx/components/input_output/text_output.py +29 -0
  301. lfx/components/jigsawstack/__init__.py +23 -0
  302. lfx/components/jigsawstack/ai_scrape.py +126 -0
  303. lfx/components/jigsawstack/ai_web_search.py +136 -0
  304. lfx/components/jigsawstack/file_read.py +115 -0
  305. lfx/components/jigsawstack/file_upload.py +94 -0
  306. lfx/components/jigsawstack/image_generation.py +205 -0
  307. lfx/components/jigsawstack/nsfw.py +60 -0
  308. lfx/components/jigsawstack/object_detection.py +124 -0
  309. lfx/components/jigsawstack/sentiment.py +112 -0
  310. lfx/components/jigsawstack/text_to_sql.py +90 -0
  311. lfx/components/jigsawstack/text_translate.py +77 -0
  312. lfx/components/jigsawstack/vocr.py +107 -0
  313. lfx/components/langchain_utilities/__init__.py +109 -0
  314. lfx/components/langchain_utilities/character.py +53 -0
  315. lfx/components/langchain_utilities/conversation.py +59 -0
  316. lfx/components/langchain_utilities/csv_agent.py +107 -0
  317. lfx/components/langchain_utilities/fake_embeddings.py +26 -0
  318. lfx/components/langchain_utilities/html_link_extractor.py +35 -0
  319. lfx/components/langchain_utilities/json_agent.py +45 -0
  320. lfx/components/langchain_utilities/langchain_hub.py +126 -0
  321. lfx/components/langchain_utilities/language_recursive.py +49 -0
  322. lfx/components/langchain_utilities/language_semantic.py +138 -0
  323. lfx/components/langchain_utilities/llm_checker.py +39 -0
  324. lfx/components/langchain_utilities/llm_math.py +42 -0
  325. lfx/components/langchain_utilities/natural_language.py +61 -0
  326. lfx/components/langchain_utilities/openai_tools.py +53 -0
  327. lfx/components/langchain_utilities/openapi.py +48 -0
  328. lfx/components/langchain_utilities/recursive_character.py +60 -0
  329. lfx/components/langchain_utilities/retrieval_qa.py +83 -0
  330. lfx/components/langchain_utilities/runnable_executor.py +137 -0
  331. lfx/components/langchain_utilities/self_query.py +80 -0
  332. lfx/components/langchain_utilities/spider.py +142 -0
  333. lfx/components/langchain_utilities/sql.py +40 -0
  334. lfx/components/langchain_utilities/sql_database.py +35 -0
  335. lfx/components/langchain_utilities/sql_generator.py +78 -0
  336. lfx/components/langchain_utilities/tool_calling.py +59 -0
  337. lfx/components/langchain_utilities/vector_store_info.py +49 -0
  338. lfx/components/langchain_utilities/vector_store_router.py +33 -0
  339. lfx/components/langchain_utilities/xml_agent.py +71 -0
  340. lfx/components/langwatch/__init__.py +3 -0
  341. lfx/components/langwatch/langwatch.py +278 -0
  342. lfx/components/link_extractors/__init__.py +3 -0
  343. lfx/components/lmstudio/__init__.py +34 -0
  344. lfx/components/lmstudio/lmstudioembeddings.py +89 -0
  345. lfx/components/lmstudio/lmstudiomodel.py +129 -0
  346. lfx/components/logic/__init__.py +52 -0
  347. lfx/components/logic/conditional_router.py +171 -0
  348. lfx/components/logic/data_conditional_router.py +125 -0
  349. lfx/components/logic/flow_tool.py +110 -0
  350. lfx/components/logic/listen.py +29 -0
  351. lfx/components/logic/loop.py +125 -0
  352. lfx/components/logic/notify.py +88 -0
  353. lfx/components/logic/pass_message.py +35 -0
  354. lfx/components/logic/run_flow.py +71 -0
  355. lfx/components/logic/sub_flow.py +114 -0
  356. lfx/components/maritalk/__init__.py +32 -0
  357. lfx/components/maritalk/maritalk.py +52 -0
  358. lfx/components/mem0/__init__.py +3 -0
  359. lfx/components/mem0/mem0_chat_memory.py +136 -0
  360. lfx/components/milvus/__init__.py +34 -0
  361. lfx/components/milvus/milvus.py +115 -0
  362. lfx/components/mistral/__init__.py +37 -0
  363. lfx/components/mistral/mistral.py +114 -0
  364. lfx/components/mistral/mistral_embeddings.py +58 -0
  365. lfx/components/models/__init__.py +34 -0
  366. lfx/components/models/embedding_model.py +114 -0
  367. lfx/components/models/language_model.py +144 -0
  368. lfx/components/mongodb/__init__.py +34 -0
  369. lfx/components/mongodb/mongodb_atlas.py +213 -0
  370. lfx/components/needle/__init__.py +3 -0
  371. lfx/components/needle/needle.py +104 -0
  372. lfx/components/notdiamond/__init__.py +34 -0
  373. lfx/components/notdiamond/notdiamond.py +228 -0
  374. lfx/components/novita/__init__.py +32 -0
  375. lfx/components/novita/novita.py +130 -0
  376. lfx/components/nvidia/__init__.py +57 -0
  377. lfx/components/nvidia/nvidia.py +157 -0
  378. lfx/components/nvidia/nvidia_embedding.py +77 -0
  379. lfx/components/nvidia/nvidia_ingest.py +317 -0
  380. lfx/components/nvidia/nvidia_rerank.py +63 -0
  381. lfx/components/nvidia/system_assist.py +65 -0
  382. lfx/components/olivya/__init__.py +3 -0
  383. lfx/components/olivya/olivya.py +116 -0
  384. lfx/components/ollama/__init__.py +37 -0
  385. lfx/components/ollama/ollama.py +330 -0
  386. lfx/components/ollama/ollama_embeddings.py +106 -0
  387. lfx/components/openai/__init__.py +37 -0
  388. lfx/components/openai/openai.py +100 -0
  389. lfx/components/openai/openai_chat_model.py +176 -0
  390. lfx/components/openrouter/__init__.py +32 -0
  391. lfx/components/openrouter/openrouter.py +202 -0
  392. lfx/components/output_parsers/__init__.py +3 -0
  393. lfx/components/perplexity/__init__.py +34 -0
  394. lfx/components/perplexity/perplexity.py +75 -0
  395. lfx/components/pgvector/__init__.py +34 -0
  396. lfx/components/pgvector/pgvector.py +72 -0
  397. lfx/components/pinecone/__init__.py +34 -0
  398. lfx/components/pinecone/pinecone.py +134 -0
  399. lfx/components/processing/__init__.py +117 -0
  400. lfx/components/processing/alter_metadata.py +108 -0
  401. lfx/components/processing/batch_run.py +205 -0
  402. lfx/components/processing/combine_text.py +39 -0
  403. lfx/components/processing/converter.py +159 -0
  404. lfx/components/processing/create_data.py +110 -0
  405. lfx/components/processing/data_operations.py +438 -0
  406. lfx/components/processing/data_to_dataframe.py +70 -0
  407. lfx/components/processing/dataframe_operations.py +313 -0
  408. lfx/components/processing/extract_key.py +53 -0
  409. lfx/components/processing/filter_data.py +42 -0
  410. lfx/components/processing/filter_data_values.py +88 -0
  411. lfx/components/processing/json_cleaner.py +103 -0
  412. lfx/components/processing/lambda_filter.py +154 -0
  413. lfx/components/processing/llm_router.py +499 -0
  414. lfx/components/processing/merge_data.py +90 -0
  415. lfx/components/processing/message_to_data.py +36 -0
  416. lfx/components/processing/parse_data.py +70 -0
  417. lfx/components/processing/parse_dataframe.py +68 -0
  418. lfx/components/processing/parse_json_data.py +90 -0
  419. lfx/components/processing/parser.py +143 -0
  420. lfx/components/processing/prompt.py +67 -0
  421. lfx/components/processing/python_repl_core.py +98 -0
  422. lfx/components/processing/regex.py +82 -0
  423. lfx/components/processing/save_file.py +225 -0
  424. lfx/components/processing/select_data.py +48 -0
  425. lfx/components/processing/split_text.py +141 -0
  426. lfx/components/processing/structured_output.py +202 -0
  427. lfx/components/processing/update_data.py +160 -0
  428. lfx/components/prototypes/__init__.py +34 -0
  429. lfx/components/prototypes/python_function.py +73 -0
  430. lfx/components/qdrant/__init__.py +34 -0
  431. lfx/components/qdrant/qdrant.py +109 -0
  432. lfx/components/redis/__init__.py +37 -0
  433. lfx/components/redis/redis.py +89 -0
  434. lfx/components/redis/redis_chat.py +43 -0
  435. lfx/components/sambanova/__init__.py +32 -0
  436. lfx/components/sambanova/sambanova.py +84 -0
  437. lfx/components/scrapegraph/__init__.py +40 -0
  438. lfx/components/scrapegraph/scrapegraph_markdownify_api.py +64 -0
  439. lfx/components/scrapegraph/scrapegraph_search_api.py +64 -0
  440. lfx/components/scrapegraph/scrapegraph_smart_scraper_api.py +71 -0
  441. lfx/components/searchapi/__init__.py +34 -0
  442. lfx/components/searchapi/search.py +79 -0
  443. lfx/components/serpapi/__init__.py +3 -0
  444. lfx/components/serpapi/serp.py +115 -0
  445. lfx/components/supabase/__init__.py +34 -0
  446. lfx/components/supabase/supabase.py +76 -0
  447. lfx/components/tavily/__init__.py +4 -0
  448. lfx/components/tavily/tavily_extract.py +117 -0
  449. lfx/components/tavily/tavily_search.py +212 -0
  450. lfx/components/textsplitters/__init__.py +3 -0
  451. lfx/components/toolkits/__init__.py +3 -0
  452. lfx/components/tools/__init__.py +72 -0
  453. lfx/components/tools/calculator.py +108 -0
  454. lfx/components/tools/google_search_api.py +45 -0
  455. lfx/components/tools/google_serper_api.py +115 -0
  456. lfx/components/tools/python_code_structured_tool.py +327 -0
  457. lfx/components/tools/python_repl.py +97 -0
  458. lfx/components/tools/search_api.py +87 -0
  459. lfx/components/tools/searxng.py +145 -0
  460. lfx/components/tools/serp_api.py +119 -0
  461. lfx/components/tools/tavily_search_tool.py +344 -0
  462. lfx/components/tools/wikidata_api.py +102 -0
  463. lfx/components/tools/wikipedia_api.py +49 -0
  464. lfx/components/tools/yahoo_finance.py +129 -0
  465. lfx/components/twelvelabs/__init__.py +52 -0
  466. lfx/components/twelvelabs/convert_astra_results.py +84 -0
  467. lfx/components/twelvelabs/pegasus_index.py +311 -0
  468. lfx/components/twelvelabs/split_video.py +291 -0
  469. lfx/components/twelvelabs/text_embeddings.py +57 -0
  470. lfx/components/twelvelabs/twelvelabs_pegasus.py +408 -0
  471. lfx/components/twelvelabs/video_embeddings.py +100 -0
  472. lfx/components/twelvelabs/video_file.py +179 -0
  473. lfx/components/unstructured/__init__.py +3 -0
  474. lfx/components/unstructured/unstructured.py +121 -0
  475. lfx/components/upstash/__init__.py +34 -0
  476. lfx/components/upstash/upstash.py +124 -0
  477. lfx/components/vectara/__init__.py +37 -0
  478. lfx/components/vectara/vectara.py +97 -0
  479. lfx/components/vectara/vectara_rag.py +164 -0
  480. lfx/components/vectorstores/__init__.py +40 -0
  481. lfx/components/vectorstores/astradb.py +1285 -0
  482. lfx/components/vectorstores/astradb_graph.py +319 -0
  483. lfx/components/vectorstores/cassandra.py +264 -0
  484. lfx/components/vectorstores/cassandra_graph.py +238 -0
  485. lfx/components/vectorstores/chroma.py +167 -0
  486. lfx/components/vectorstores/clickhouse.py +135 -0
  487. lfx/components/vectorstores/couchbase.py +102 -0
  488. lfx/components/vectorstores/elasticsearch.py +267 -0
  489. lfx/components/vectorstores/faiss.py +111 -0
  490. lfx/components/vectorstores/graph_rag.py +141 -0
  491. lfx/components/vectorstores/hcd.py +314 -0
  492. lfx/components/vectorstores/local_db.py +261 -0
  493. lfx/components/vectorstores/milvus.py +115 -0
  494. lfx/components/vectorstores/mongodb_atlas.py +213 -0
  495. lfx/components/vectorstores/opensearch.py +243 -0
  496. lfx/components/vectorstores/pgvector.py +72 -0
  497. lfx/components/vectorstores/pinecone.py +134 -0
  498. lfx/components/vectorstores/qdrant.py +109 -0
  499. lfx/components/vectorstores/supabase.py +76 -0
  500. lfx/components/vectorstores/upstash.py +124 -0
  501. lfx/components/vectorstores/vectara.py +97 -0
  502. lfx/components/vectorstores/vectara_rag.py +164 -0
  503. lfx/components/vectorstores/weaviate.py +89 -0
  504. lfx/components/vertexai/__init__.py +37 -0
  505. lfx/components/vertexai/vertexai.py +71 -0
  506. lfx/components/vertexai/vertexai_embeddings.py +67 -0
  507. lfx/components/weaviate/__init__.py +34 -0
  508. lfx/components/weaviate/weaviate.py +89 -0
  509. lfx/components/wikipedia/__init__.py +4 -0
  510. lfx/components/wikipedia/wikidata.py +86 -0
  511. lfx/components/wikipedia/wikipedia.py +53 -0
  512. lfx/components/wolframalpha/__init__.py +3 -0
  513. lfx/components/wolframalpha/wolfram_alpha_api.py +54 -0
  514. lfx/components/xai/__init__.py +32 -0
  515. lfx/components/xai/xai.py +167 -0
  516. lfx/components/yahoosearch/__init__.py +3 -0
  517. lfx/components/yahoosearch/yahoo.py +137 -0
  518. lfx/components/youtube/__init__.py +52 -0
  519. lfx/components/youtube/channel.py +227 -0
  520. lfx/components/youtube/comments.py +231 -0
  521. lfx/components/youtube/playlist.py +33 -0
  522. lfx/components/youtube/search.py +120 -0
  523. lfx/components/youtube/trending.py +285 -0
  524. lfx/components/youtube/video_details.py +263 -0
  525. lfx/components/youtube/youtube_transcripts.py +118 -0
  526. lfx/components/zep/__init__.py +3 -0
  527. lfx/components/zep/zep.py +44 -0
  528. lfx/constants.py +6 -0
  529. lfx/custom/__init__.py +7 -0
  530. lfx/custom/attributes.py +86 -0
  531. lfx/custom/code_parser/__init__.py +3 -0
  532. lfx/custom/code_parser/code_parser.py +361 -0
  533. lfx/custom/custom_component/__init__.py +0 -0
  534. lfx/custom/custom_component/base_component.py +128 -0
  535. lfx/custom/custom_component/component.py +1808 -0
  536. lfx/custom/custom_component/component_with_cache.py +8 -0
  537. lfx/custom/custom_component/custom_component.py +588 -0
  538. lfx/custom/dependency_analyzer.py +165 -0
  539. lfx/custom/directory_reader/__init__.py +3 -0
  540. lfx/custom/directory_reader/directory_reader.py +359 -0
  541. lfx/custom/directory_reader/utils.py +171 -0
  542. lfx/custom/eval.py +12 -0
  543. lfx/custom/schema.py +32 -0
  544. lfx/custom/tree_visitor.py +21 -0
  545. lfx/custom/utils.py +877 -0
  546. lfx/custom/validate.py +488 -0
  547. lfx/events/__init__.py +1 -0
  548. lfx/events/event_manager.py +110 -0
  549. lfx/exceptions/__init__.py +0 -0
  550. lfx/exceptions/component.py +15 -0
  551. lfx/field_typing/__init__.py +91 -0
  552. lfx/field_typing/constants.py +215 -0
  553. lfx/field_typing/range_spec.py +35 -0
  554. lfx/graph/__init__.py +6 -0
  555. lfx/graph/edge/__init__.py +0 -0
  556. lfx/graph/edge/base.py +277 -0
  557. lfx/graph/edge/schema.py +119 -0
  558. lfx/graph/edge/utils.py +0 -0
  559. lfx/graph/graph/__init__.py +0 -0
  560. lfx/graph/graph/ascii.py +202 -0
  561. lfx/graph/graph/base.py +2238 -0
  562. lfx/graph/graph/constants.py +63 -0
  563. lfx/graph/graph/runnable_vertices_manager.py +133 -0
  564. lfx/graph/graph/schema.py +52 -0
  565. lfx/graph/graph/state_model.py +66 -0
  566. lfx/graph/graph/utils.py +1024 -0
  567. lfx/graph/schema.py +75 -0
  568. lfx/graph/state/__init__.py +0 -0
  569. lfx/graph/state/model.py +237 -0
  570. lfx/graph/utils.py +200 -0
  571. lfx/graph/vertex/__init__.py +0 -0
  572. lfx/graph/vertex/base.py +823 -0
  573. lfx/graph/vertex/constants.py +0 -0
  574. lfx/graph/vertex/exceptions.py +4 -0
  575. lfx/graph/vertex/param_handler.py +264 -0
  576. lfx/graph/vertex/schema.py +26 -0
  577. lfx/graph/vertex/utils.py +19 -0
  578. lfx/graph/vertex/vertex_types.py +489 -0
  579. lfx/helpers/__init__.py +1 -0
  580. lfx/helpers/base_model.py +71 -0
  581. lfx/helpers/custom.py +13 -0
  582. lfx/helpers/data.py +167 -0
  583. lfx/helpers/flow.py +194 -0
  584. lfx/inputs/__init__.py +68 -0
  585. lfx/inputs/constants.py +2 -0
  586. lfx/inputs/input_mixin.py +328 -0
  587. lfx/inputs/inputs.py +714 -0
  588. lfx/inputs/validators.py +19 -0
  589. lfx/interface/__init__.py +6 -0
  590. lfx/interface/components.py +489 -0
  591. lfx/interface/importing/__init__.py +5 -0
  592. lfx/interface/importing/utils.py +39 -0
  593. lfx/interface/initialize/__init__.py +3 -0
  594. lfx/interface/initialize/loading.py +224 -0
  595. lfx/interface/listing.py +26 -0
  596. lfx/interface/run.py +16 -0
  597. lfx/interface/utils.py +111 -0
  598. lfx/io/__init__.py +63 -0
  599. lfx/io/schema.py +289 -0
  600. lfx/load/__init__.py +8 -0
  601. lfx/load/load.py +256 -0
  602. lfx/load/utils.py +99 -0
  603. lfx/log/__init__.py +5 -0
  604. lfx/log/logger.py +385 -0
  605. lfx/memory/__init__.py +90 -0
  606. lfx/memory/stubs.py +283 -0
  607. lfx/processing/__init__.py +1 -0
  608. lfx/processing/process.py +238 -0
  609. lfx/processing/utils.py +25 -0
  610. lfx/py.typed +0 -0
  611. lfx/schema/__init__.py +66 -0
  612. lfx/schema/artifact.py +83 -0
  613. lfx/schema/content_block.py +62 -0
  614. lfx/schema/content_types.py +91 -0
  615. lfx/schema/data.py +308 -0
  616. lfx/schema/dataframe.py +210 -0
  617. lfx/schema/dotdict.py +74 -0
  618. lfx/schema/encoders.py +13 -0
  619. lfx/schema/graph.py +47 -0
  620. lfx/schema/image.py +131 -0
  621. lfx/schema/json_schema.py +141 -0
  622. lfx/schema/log.py +61 -0
  623. lfx/schema/message.py +473 -0
  624. lfx/schema/openai_responses_schemas.py +74 -0
  625. lfx/schema/properties.py +41 -0
  626. lfx/schema/schema.py +171 -0
  627. lfx/schema/serialize.py +13 -0
  628. lfx/schema/table.py +140 -0
  629. lfx/schema/validators.py +114 -0
  630. lfx/serialization/__init__.py +5 -0
  631. lfx/serialization/constants.py +2 -0
  632. lfx/serialization/serialization.py +314 -0
  633. lfx/services/__init__.py +23 -0
  634. lfx/services/base.py +28 -0
  635. lfx/services/cache/__init__.py +6 -0
  636. lfx/services/cache/base.py +183 -0
  637. lfx/services/cache/service.py +166 -0
  638. lfx/services/cache/utils.py +169 -0
  639. lfx/services/chat/__init__.py +1 -0
  640. lfx/services/chat/config.py +2 -0
  641. lfx/services/chat/schema.py +10 -0
  642. lfx/services/deps.py +129 -0
  643. lfx/services/factory.py +19 -0
  644. lfx/services/initialize.py +19 -0
  645. lfx/services/interfaces.py +103 -0
  646. lfx/services/manager.py +172 -0
  647. lfx/services/schema.py +20 -0
  648. lfx/services/session.py +82 -0
  649. lfx/services/settings/__init__.py +3 -0
  650. lfx/services/settings/auth.py +130 -0
  651. lfx/services/settings/base.py +539 -0
  652. lfx/services/settings/constants.py +31 -0
  653. lfx/services/settings/factory.py +23 -0
  654. lfx/services/settings/feature_flags.py +12 -0
  655. lfx/services/settings/service.py +35 -0
  656. lfx/services/settings/utils.py +40 -0
  657. lfx/services/shared_component_cache/__init__.py +1 -0
  658. lfx/services/shared_component_cache/factory.py +30 -0
  659. lfx/services/shared_component_cache/service.py +9 -0
  660. lfx/services/storage/__init__.py +5 -0
  661. lfx/services/storage/local.py +155 -0
  662. lfx/services/storage/service.py +54 -0
  663. lfx/services/tracing/__init__.py +1 -0
  664. lfx/services/tracing/service.py +21 -0
  665. lfx/settings.py +6 -0
  666. lfx/template/__init__.py +6 -0
  667. lfx/template/field/__init__.py +0 -0
  668. lfx/template/field/base.py +257 -0
  669. lfx/template/field/prompt.py +15 -0
  670. lfx/template/frontend_node/__init__.py +6 -0
  671. lfx/template/frontend_node/base.py +212 -0
  672. lfx/template/frontend_node/constants.py +65 -0
  673. lfx/template/frontend_node/custom_components.py +79 -0
  674. lfx/template/template/__init__.py +0 -0
  675. lfx/template/template/base.py +100 -0
  676. lfx/template/utils.py +217 -0
  677. lfx/type_extraction/__init__.py +19 -0
  678. lfx/type_extraction/type_extraction.py +75 -0
  679. lfx/type_extraction.py +80 -0
  680. lfx/utils/__init__.py +1 -0
  681. lfx/utils/async_helpers.py +42 -0
  682. lfx/utils/component_utils.py +154 -0
  683. lfx/utils/concurrency.py +60 -0
  684. lfx/utils/connection_string_parser.py +11 -0
  685. lfx/utils/constants.py +205 -0
  686. lfx/utils/data_structure.py +212 -0
  687. lfx/utils/exceptions.py +22 -0
  688. lfx/utils/helpers.py +28 -0
  689. lfx/utils/image.py +73 -0
  690. lfx/utils/lazy_load.py +15 -0
  691. lfx/utils/request_utils.py +18 -0
  692. lfx/utils/schemas.py +139 -0
  693. lfx/utils/util.py +481 -0
  694. lfx/utils/util_strings.py +56 -0
  695. lfx/utils/version.py +24 -0
  696. lfx_nightly-0.1.11.dev0.dist-info/METADATA +293 -0
  697. lfx_nightly-0.1.11.dev0.dist-info/RECORD +699 -0
  698. lfx_nightly-0.1.11.dev0.dist-info/WHEEL +4 -0
  699. lfx_nightly-0.1.11.dev0.dist-info/entry_points.txt +2 -0
lfx/cli/serve_app.py ADDED
@@ -0,0 +1,546 @@
1
+ """FastAPI application factory for serving **multiple** LFX graphs at once.
2
+
3
+ This module is used by the CLI *serve* command when the provided path is a
4
+ folder containing multiple ``*.json`` flow files. Each flow is exposed under
5
+ its own router prefix::
6
+
7
+ /flows/{flow_id}/run - POST - execute the flow
8
+ /flows/{flow_id}/info - GET - metadata
9
+
10
+ A global ``/flows`` endpoint lists all available flows and returns a JSON array
11
+ of metadata objects, allowing API consumers to discover IDs without guessing.
12
+
13
+ Authentication behaves exactly like the single-flow serving: all execution
14
+ endpoints require the ``x-api-key`` header (or query parameter) validated by
15
+ :func:`lfx.cli.commands.verify_api_key`.
16
+ """
17
+
18
+ from __future__ import annotations
19
+
20
+ import asyncio
21
+ import time
22
+ from copy import deepcopy
23
+ from typing import TYPE_CHECKING, Annotated, Any
24
+
25
+ from fastapi import APIRouter, Depends, FastAPI, HTTPException, Security
26
+ from fastapi.responses import StreamingResponse
27
+ from fastapi.security import APIKeyHeader, APIKeyQuery
28
+ from pydantic import BaseModel, Field
29
+
30
+ from lfx.cli.common import execute_graph_with_capture, extract_result_data, get_api_key
31
+ from lfx.log.logger import logger
32
+
33
+ if TYPE_CHECKING:
34
+ from collections.abc import AsyncGenerator, Callable
35
+ from pathlib import Path
36
+
37
+ from lfx.graph import Graph
38
+
39
+ # Security - use the same pattern as Langflow main API
40
+ API_KEY_NAME = "x-api-key"
41
+ api_key_query = APIKeyQuery(name=API_KEY_NAME, scheme_name="API key query", auto_error=False)
42
+ api_key_header = APIKeyHeader(name=API_KEY_NAME, scheme_name="API key header", auto_error=False)
43
+
44
+
45
+ def verify_api_key(
46
+ query_param: Annotated[str | None, Security(api_key_query)],
47
+ header_param: Annotated[str | None, Security(api_key_header)],
48
+ ) -> str:
49
+ """Verify API key from query parameter or header."""
50
+ provided_key = query_param or header_param
51
+ if not provided_key:
52
+ raise HTTPException(status_code=401, detail="API key required")
53
+
54
+ try:
55
+ expected_key = get_api_key()
56
+ if provided_key != expected_key:
57
+ raise HTTPException(status_code=401, detail="Invalid API key")
58
+ except ValueError as e:
59
+ raise HTTPException(status_code=500, detail=str(e)) from e
60
+
61
+ return provided_key
62
+
63
+
64
+ def _analyze_graph_structure(graph: Graph) -> dict[str, Any]:
65
+ """Analyze the graph structure to extract dynamic documentation information.
66
+
67
+ Args:
68
+ graph: The LFX graph to analyze
69
+
70
+ Returns:
71
+ dict: Graph analysis including components, input/output types, and flow details
72
+ """
73
+ analysis: dict[str, Any] = {
74
+ "components": [],
75
+ "input_types": set(),
76
+ "output_types": set(),
77
+ "node_count": 0,
78
+ "edge_count": 0,
79
+ "entry_points": [],
80
+ "exit_points": [],
81
+ }
82
+
83
+ try:
84
+ # Analyze nodes
85
+ for node_id, node in graph.nodes.items():
86
+ analysis["node_count"] += 1
87
+ component_info = {
88
+ "id": node_id,
89
+ "type": node.data.get("type", "Unknown"),
90
+ "name": node.data.get("display_name", node.data.get("type", "Unknown")),
91
+ "description": node.data.get("description", ""),
92
+ "template": node.data.get("template", {}),
93
+ }
94
+ analysis["components"].append(component_info)
95
+
96
+ # Identify entry points (nodes with no incoming edges)
97
+ if not any(edge.source == node_id for edge in graph.edges):
98
+ analysis["entry_points"].append(component_info)
99
+
100
+ # Identify exit points (nodes with no outgoing edges)
101
+ if not any(edge.target == node_id for edge in graph.edges):
102
+ analysis["exit_points"].append(component_info)
103
+
104
+ # Analyze edges
105
+ analysis["edge_count"] = len(graph.edges)
106
+
107
+ # Try to determine input/output types from entry/exit points
108
+ for entry in analysis["entry_points"]:
109
+ template = entry.get("template", {})
110
+ for field_config in template.values():
111
+ if field_config.get("type") in ["str", "text", "string"]:
112
+ analysis["input_types"].add("text")
113
+ elif field_config.get("type") in ["int", "float", "number"]:
114
+ analysis["input_types"].add("numeric")
115
+ elif field_config.get("type") in ["file", "path"]:
116
+ analysis["input_types"].add("file")
117
+
118
+ for exit_point in analysis["exit_points"]:
119
+ template = exit_point.get("template", {})
120
+ for field_config in template.values():
121
+ if field_config.get("type") in ["str", "text", "string"]:
122
+ analysis["output_types"].add("text")
123
+ elif field_config.get("type") in ["int", "float", "number"]:
124
+ analysis["output_types"].add("numeric")
125
+ elif field_config.get("type") in ["file", "path"]:
126
+ analysis["output_types"].add("file")
127
+
128
+ except (KeyError, AttributeError):
129
+ # If analysis fails, provide basic info
130
+ analysis["components"] = [{"type": "Unknown", "name": "Graph Component"}]
131
+ analysis["input_types"] = {"text"}
132
+ analysis["output_types"] = {"text"}
133
+
134
+ # Convert sets to lists for JSON serialization
135
+ analysis["input_types"] = list(analysis["input_types"])
136
+ analysis["output_types"] = list(analysis["output_types"])
137
+
138
+ return analysis
139
+
140
+
141
+ def _generate_dynamic_run_description(graph: Graph) -> str:
142
+ """Generate dynamic description for the /run endpoint based on graph analysis.
143
+
144
+ Args:
145
+ graph: The LFX graph
146
+
147
+ Returns:
148
+ str: Dynamic description for the /run endpoint
149
+ """
150
+ analysis = _analyze_graph_structure(graph)
151
+
152
+ # Determine input examples based on entry points
153
+ input_examples = []
154
+ for entry in analysis["entry_points"]:
155
+ template = entry.get("template", {})
156
+ for field_name, field_config in template.items():
157
+ if field_config.get("type") in ["str", "text", "string"]:
158
+ input_examples.append(f'"{field_name}": "Your input text here"')
159
+ elif field_config.get("type") in ["int", "float", "number"]:
160
+ input_examples.append(f'"{field_name}": 42')
161
+ elif field_config.get("type") in ["file", "path"]:
162
+ input_examples.append(f'"{field_name}": "/path/to/file.txt"')
163
+
164
+ if not input_examples:
165
+ input_examples = ['"input_value": "Your input text here"']
166
+
167
+ # Determine output examples based on exit points
168
+ output_examples = []
169
+ for exit_point in analysis["exit_points"]:
170
+ template = exit_point.get("template", {})
171
+ for field_name, field_config in template.items():
172
+ if field_config.get("type") in ["str", "text", "string"]:
173
+ output_examples.append(f'"{field_name}": "Processed result"')
174
+ elif field_config.get("type") in ["int", "float", "number"]:
175
+ output_examples.append(f'"{field_name}": 123')
176
+ elif field_config.get("type") in ["file", "path"]:
177
+ output_examples.append(f'"{field_name}": "/path/to/output.txt"')
178
+
179
+ if not output_examples:
180
+ output_examples = ['"result": "Processed result"']
181
+
182
+ description_parts = [
183
+ f"Execute the deployed LFX graph with {analysis['node_count']} components.",
184
+ "",
185
+ "**Graph Analysis**:",
186
+ f"- Entry points: {len(analysis['entry_points'])}",
187
+ f"- Exit points: {len(analysis['exit_points'])}",
188
+ f"- Input types: {', '.join(analysis['input_types']) if analysis['input_types'] else 'text'}",
189
+ f"- Output types: {', '.join(analysis['output_types']) if analysis['output_types'] else 'text'}",
190
+ "",
191
+ "**Authentication Required**: Include your API key in the `x-api-key` header or as a query parameter.",
192
+ "",
193
+ "**Example Request**:",
194
+ "```json",
195
+ "{",
196
+ f" {', '.join(input_examples)}",
197
+ "}",
198
+ "```",
199
+ "",
200
+ "**Example Response**:",
201
+ "```json",
202
+ "{",
203
+ f" {', '.join(output_examples)},",
204
+ ' "success": true,',
205
+ ' "logs": "Graph execution completed successfully",',
206
+ ' "type": "message",',
207
+ ' "component": "FinalComponent"',
208
+ "}",
209
+ "```",
210
+ ]
211
+
212
+ return "\n".join(description_parts)
213
+
214
+
215
+ class FlowMeta(BaseModel):
216
+ """Metadata returned by the ``/flows`` endpoint."""
217
+
218
+ id: str = Field(..., description="Deterministic flow identifier (UUIDv5)")
219
+ relative_path: str = Field(..., description="Path of the flow JSON relative to the deployed folder")
220
+ title: str = Field(..., description="Human-readable title (filename stem if unknown)")
221
+ description: str | None = Field(None, description="Optional flow description")
222
+
223
+
224
+ class RunRequest(BaseModel):
225
+ """Request model for executing a LFX flow."""
226
+
227
+ input_value: str = Field(..., description="Input value passed to the flow")
228
+
229
+
230
+ class StreamRequest(BaseModel):
231
+ """Request model for streaming execution of a LFX flow."""
232
+
233
+ input_value: str = Field(..., description="Input value passed to the flow")
234
+ input_type: str = Field(default="chat", description="Type of input (chat, text)")
235
+ output_type: str = Field(default="chat", description="Type of output (chat, text, debug, any)")
236
+ output_component: str | None = Field(default=None, description="Specific output component to stream from")
237
+ session_id: str | None = Field(default=None, description="Session ID for maintaining conversation state")
238
+ tweaks: dict[str, Any] | None = Field(default=None, description="Optional tweaks to modify flow behavior")
239
+
240
+
241
+ class RunResponse(BaseModel):
242
+ """Response model mirroring the single-flow server."""
243
+
244
+ result: str = Field(..., description="The output result from the flow execution")
245
+ success: bool = Field(..., description="Whether execution was successful")
246
+ logs: str = Field("", description="Captured logs from execution")
247
+ type: str = Field("message", description="Type of result")
248
+ component: str = Field("", description="Component that generated the result")
249
+
250
+
251
+ class ErrorResponse(BaseModel):
252
+ error: str = Field(..., description="Error message")
253
+ success: bool = Field(default=False, description="Always false for errors")
254
+
255
+
256
+ # -----------------------------------------------------------------------------
257
+ # Streaming helper functions
258
+ # -----------------------------------------------------------------------------
259
+
260
+
261
+ async def consume_and_yield(queue: asyncio.Queue, client_consumed_queue: asyncio.Queue) -> AsyncGenerator:
262
+ """Consumes events from a queue and yields them to the client while tracking timing metrics.
263
+
264
+ This coroutine continuously pulls events from the input queue and yields them to the client.
265
+ It tracks timing metrics for how long events spend in the queue and how long the client takes
266
+ to process them.
267
+
268
+ Args:
269
+ queue (asyncio.Queue): The queue containing events to be consumed and yielded
270
+ client_consumed_queue (asyncio.Queue): A queue for tracking when the client has consumed events
271
+
272
+ Yields:
273
+ The value from each event in the queue
274
+
275
+ Notes:
276
+ - Events are tuples of (event_id, value, put_time)
277
+ - Breaks the loop when receiving a None value, signaling completion
278
+ - Tracks and logs timing metrics for queue time and client processing time
279
+ - Notifies client consumption via client_consumed_queue
280
+ """
281
+ while True:
282
+ event_id, value, put_time = await queue.get()
283
+ if value is None:
284
+ break
285
+ get_time = time.time()
286
+ yield value
287
+ get_time_yield = time.time()
288
+ client_consumed_queue.put_nowait(event_id)
289
+ logger.debug(
290
+ f"consumed event {event_id} "
291
+ f"(time in queue, {get_time - put_time:.4f}, "
292
+ f"client {get_time_yield - get_time:.4f})"
293
+ )
294
+
295
+
296
+ async def run_flow_generator_for_serve(
297
+ graph: Graph,
298
+ input_request: StreamRequest,
299
+ flow_id: str,
300
+ event_manager,
301
+ client_consumed_queue: asyncio.Queue,
302
+ ) -> None:
303
+ """Executes a flow asynchronously and manages event streaming to the client.
304
+
305
+ This coroutine runs a flow with streaming enabled and handles the event lifecycle,
306
+ including success completion and error scenarios.
307
+
308
+ Args:
309
+ graph (Graph): The graph to execute
310
+ input_request (StreamRequest): The input parameters for the flow
311
+ flow_id (str): The ID of the flow being executed
312
+ event_manager: Manages the streaming of events to the client
313
+ client_consumed_queue (asyncio.Queue): Tracks client consumption of events
314
+
315
+ Events Generated:
316
+ - "add_message": Sent when new messages are added during flow execution
317
+ - "token": Sent for each token generated during streaming
318
+ - "end": Sent when flow execution completes, includes final result
319
+ - "error": Sent if an error occurs during execution
320
+
321
+ Notes:
322
+ - Runs the flow with streaming enabled via execute_graph_with_capture()
323
+ - On success, sends the final result via event_manager.on_end()
324
+ - On error, logs the error and sends it via event_manager.on_error()
325
+ - Always sends a final None event to signal completion
326
+ """
327
+ try:
328
+ # For the serve app, we'll use execute_graph_with_capture with streaming
329
+ # Note: This is a simplified version. In a full implementation, you might want
330
+ # to integrate with the full LFX streaming pipeline from endpoints.py
331
+ results, logs = await execute_graph_with_capture(graph, input_request.input_value)
332
+ result_data = extract_result_data(results, logs)
333
+
334
+ # Send the final result
335
+ event_manager.on_end(data={"result": result_data})
336
+ await client_consumed_queue.get()
337
+ except Exception as e: # noqa: BLE001
338
+ logger.error(f"Error running flow {flow_id}: {e}")
339
+ event_manager.on_error(data={"error": str(e)})
340
+ finally:
341
+ await event_manager.queue.put((None, None, time.time()))
342
+
343
+
344
+ # -----------------------------------------------------------------------------
345
+ # Application factory
346
+ # -----------------------------------------------------------------------------
347
+
348
+
349
+ def create_multi_serve_app(
350
+ *,
351
+ root_dir: Path, # noqa: ARG001
352
+ graphs: dict[str, Graph],
353
+ metas: dict[str, FlowMeta],
354
+ verbose_print: Callable[[str], None], # noqa: ARG001
355
+ ) -> FastAPI:
356
+ """Create a FastAPI app exposing multiple LFX flows.
357
+
358
+ Parameters
359
+ ----------
360
+ root_dir
361
+ Folder originally supplied to the serve command. All *relative_path*
362
+ values are relative to this directory.
363
+ graphs
364
+ Mapping ``flow_id -> Graph`` containing prepared graph objects.
365
+ metas
366
+ Mapping ``flow_id -> FlowMeta`` containing metadata for each flow.
367
+ verbose_print
368
+ Diagnostic printer inherited from the CLI (unused, kept for backward compatibility).
369
+ """
370
+ if set(graphs) != set(metas): # pragma: no cover - sanity check
371
+ msg = "graphs and metas must contain the same keys"
372
+ raise ValueError(msg)
373
+
374
+ app = FastAPI(
375
+ title=f"LFX Multi-Flow Server ({len(graphs)})",
376
+ description=(
377
+ "This server hosts multiple LFX graphs under the `/flows/{id}` prefix. "
378
+ "Use `/flows` to list available IDs then POST your input to `/flows/{id}/run`."
379
+ ),
380
+ version="1.0.0",
381
+ )
382
+
383
+ # ------------------------------------------------------------------
384
+ # Global endpoints
385
+ # ------------------------------------------------------------------
386
+
387
+ @app.get("/flows", response_model=list[FlowMeta], tags=["info"], summary="List available flows")
388
+ async def list_flows():
389
+ """Return metadata for all flows hosted in this server."""
390
+ return list(metas.values())
391
+
392
+ @app.get("/health", tags=["info"], summary="Global health check")
393
+ async def global_health():
394
+ return {"status": "healthy", "flow_count": len(graphs)}
395
+
396
+ # ------------------------------------------------------------------
397
+ # Per-flow routers
398
+ # ------------------------------------------------------------------
399
+
400
+ def create_flow_router(flow_id: str, graph: Graph, meta: FlowMeta) -> APIRouter:
401
+ """Create a router for a specific flow to avoid loop variable binding issues."""
402
+ analysis = _analyze_graph_structure(graph)
403
+ run_description = _generate_dynamic_run_description(graph)
404
+
405
+ router = APIRouter(
406
+ prefix=f"/flows/{flow_id}",
407
+ tags=[meta.title or flow_id],
408
+ dependencies=[Depends(verify_api_key)], # Auth for all routes inside
409
+ )
410
+
411
+ @router.post(
412
+ "/run",
413
+ response_model=RunResponse,
414
+ responses={500: {"model": ErrorResponse}},
415
+ summary="Execute flow",
416
+ description=run_description,
417
+ )
418
+ async def run_flow(
419
+ request: RunRequest,
420
+ ) -> RunResponse:
421
+ try:
422
+ graph_copy = deepcopy(graph)
423
+ results, logs = await execute_graph_with_capture(graph_copy, request.input_value)
424
+ result_data = extract_result_data(results, logs)
425
+
426
+ # Debug logging
427
+ logger.debug(f"Flow {flow_id} execution completed: {len(results)} results, {len(logs)} log chars")
428
+ logger.debug(f"Flow {flow_id} result data: {result_data}")
429
+
430
+ # Check if the execution was successful
431
+ if not result_data.get("success", True):
432
+ # If the flow execution failed, return error details in the response
433
+ error_message = result_data.get("result", result_data.get("text", "No response generated"))
434
+
435
+ # Add more context to the logs when there's an error
436
+ error_logs = logs
437
+ if not error_logs.strip():
438
+ error_logs = (
439
+ f"Flow execution completed but no valid result was produced.\nResult data: {result_data}"
440
+ )
441
+
442
+ return RunResponse(
443
+ result=error_message,
444
+ success=False,
445
+ logs=error_logs,
446
+ type="error",
447
+ component=result_data.get("component", ""),
448
+ )
449
+
450
+ return RunResponse(
451
+ result=result_data.get("result", result_data.get("text", "")),
452
+ success=result_data.get("success", True),
453
+ logs=logs,
454
+ type=result_data.get("type", "message"),
455
+ component=result_data.get("component", ""),
456
+ )
457
+ except Exception as exc: # noqa: BLE001
458
+ import traceback
459
+
460
+ # Capture the full traceback for debugging
461
+ error_traceback = traceback.format_exc()
462
+ error_message = f"Flow execution failed: {exc!s}"
463
+
464
+ # Log to server console for debugging
465
+ logger.error(f"Error running flow {flow_id}: {exc}")
466
+ logger.debug(f"Full traceback for flow {flow_id}:\n{error_traceback}")
467
+
468
+ # Return error details in the API response instead of raising HTTPException
469
+ return RunResponse(
470
+ result=error_message,
471
+ success=False,
472
+ logs=f"ERROR: {error_message}\n\nFull traceback:\n{error_traceback}",
473
+ type="error",
474
+ component="",
475
+ )
476
+
477
+ @router.post(
478
+ "/stream",
479
+ response_model=None,
480
+ summary="Stream flow execution",
481
+ description=f"Stream the execution of {meta.title or flow_id} with real-time events and token streaming.",
482
+ )
483
+ async def stream_flow(
484
+ request: StreamRequest,
485
+ ) -> StreamingResponse:
486
+ """Stream the execution of the flow with real-time events."""
487
+ try:
488
+ # Import here to avoid potential circular imports
489
+ from lfx.events.event_manager import create_stream_tokens_event_manager
490
+
491
+ asyncio_queue: asyncio.Queue = asyncio.Queue()
492
+ asyncio_queue_client_consumed: asyncio.Queue = asyncio.Queue()
493
+ event_manager = create_stream_tokens_event_manager(queue=asyncio_queue)
494
+
495
+ main_task = asyncio.create_task(
496
+ run_flow_generator_for_serve(
497
+ graph=graph,
498
+ input_request=request,
499
+ flow_id=flow_id,
500
+ event_manager=event_manager,
501
+ client_consumed_queue=asyncio_queue_client_consumed,
502
+ )
503
+ )
504
+
505
+ async def on_disconnect() -> None:
506
+ logger.debug(f"Client disconnected from flow {flow_id}, closing tasks")
507
+ main_task.cancel()
508
+
509
+ return StreamingResponse(
510
+ consume_and_yield(asyncio_queue, asyncio_queue_client_consumed),
511
+ background=on_disconnect,
512
+ media_type="text/event-stream",
513
+ )
514
+ except Exception as exc: # noqa: BLE001
515
+ logger.error(f"Error setting up streaming for flow {flow_id}: {exc}")
516
+ # Return a simple error stream
517
+ error_message = f"Failed to start streaming: {exc!s}"
518
+
519
+ async def error_stream():
520
+ yield f'data: {{"error": "{error_message}", "success": false}}\n\n'
521
+
522
+ return StreamingResponse(
523
+ error_stream(),
524
+ media_type="text/event-stream",
525
+ )
526
+
527
+ @router.get("/info", summary="Flow metadata", response_model=FlowMeta)
528
+ async def flow_info():
529
+ """Return metadata and basic analysis for this flow."""
530
+ # Enrich meta with analysis data for convenience
531
+ return {
532
+ **meta.model_dump(),
533
+ "components": analysis["node_count"],
534
+ "connections": analysis["edge_count"],
535
+ "input_types": analysis["input_types"],
536
+ "output_types": analysis["output_types"],
537
+ }
538
+
539
+ return router
540
+
541
+ for flow_id, graph in graphs.items():
542
+ meta = metas[flow_id]
543
+ router = create_flow_router(flow_id, graph, meta)
544
+ app.include_router(router)
545
+
546
+ return app
lfx/cli/validation.py ADDED
@@ -0,0 +1,69 @@
1
+ """Validation utilities for CLI commands."""
2
+
3
+ import re
4
+
5
+ from lfx.graph.graph.base import Graph
6
+ from lfx.services.deps import get_settings_service
7
+
8
+
9
+ def is_valid_env_var_name(name: str) -> bool:
10
+ """Check if a string is a valid environment variable name.
11
+
12
+ Environment variable names should:
13
+ - Start with a letter or underscore
14
+ - Contain only letters, numbers, and underscores
15
+ - Not contain spaces or special characters
16
+
17
+ Args:
18
+ name: The string to validate
19
+
20
+ Returns:
21
+ bool: True if valid, False otherwise
22
+ """
23
+ # Pattern for valid environment variable names
24
+ # Must start with letter or underscore, followed by letters, numbers, or underscores
25
+ pattern = r"^[a-zA-Z_][a-zA-Z0-9_]*$"
26
+ return bool(re.match(pattern, name))
27
+
28
+
29
+ def validate_global_variables_for_env(graph: Graph) -> list[str]:
30
+ """Validate that all global variables with load_from_db=True can be used as environment variables.
31
+
32
+ When the database is not available (noop mode), global variables with load_from_db=True
33
+ are loaded from environment variables. This function checks that all such variables
34
+ have names that are valid for environment variables.
35
+
36
+ Args:
37
+ graph: The graph to validate
38
+
39
+ Returns:
40
+ list[str]: List of error messages for invalid variable names
41
+ """
42
+ errors = []
43
+ settings_service = get_settings_service()
44
+
45
+ # Check if we're in noop mode (no database)
46
+ is_noop_mode = settings_service and settings_service.settings.use_noop_database
47
+
48
+ if not is_noop_mode:
49
+ # If database is available, no need to validate
50
+ return errors
51
+
52
+ # Check all vertices for fields with load_from_db=True
53
+ for vertex in graph.vertices:
54
+ # Get the fields that have load_from_db=True
55
+ load_from_db_fields = getattr(vertex, "load_from_db_fields", [])
56
+
57
+ for field_name in load_from_db_fields:
58
+ # Get the value of the field (which should be the variable name)
59
+ field_value = vertex.params.get(field_name)
60
+
61
+ if field_value and isinstance(field_value, str) and not is_valid_env_var_name(field_value):
62
+ errors.append(
63
+ f"Component '{vertex.display_name}' (id: {vertex.id}) has field '{field_name}' "
64
+ f"with value '{field_value}' that contains invalid characters for an environment "
65
+ f"variable name. Environment variable names must start with a letter or underscore "
66
+ f"and contain only letters, numbers, and underscores (no spaces or special characters)."
67
+ )
68
+
69
+ return errors
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Any
4
+
5
+ from lfx.components._importing import import_mod
6
+
7
+ if TYPE_CHECKING:
8
+ from .faiss import FaissVectorStoreComponent
9
+
10
+ _dynamic_imports = {
11
+ "FaissVectorStoreComponent": "faiss",
12
+ }
13
+
14
+ __all__ = [
15
+ "FaissVectorStoreComponent",
16
+ ]
17
+
18
+
19
+ def __getattr__(attr_name: str) -> Any:
20
+ """Lazily import FAISS components on attribute access."""
21
+ if attr_name not in _dynamic_imports:
22
+ msg = f"module '{__name__}' has no attribute '{attr_name}'"
23
+ raise AttributeError(msg)
24
+ try:
25
+ result = import_mod(attr_name, _dynamic_imports[attr_name], __spec__.parent)
26
+ except (ModuleNotFoundError, ImportError, AttributeError) as e:
27
+ msg = f"Could not import '{attr_name}' from '{__name__}': {e}"
28
+ raise AttributeError(msg) from e
29
+ globals()[attr_name] = result
30
+ return result
31
+
32
+
33
+ def __dir__() -> list[str]:
34
+ return list(__all__)