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/common.py ADDED
@@ -0,0 +1,650 @@
1
+ """Common utilities for CLI commands."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ast
6
+ import contextlib
7
+ import importlib.metadata as importlib_metadata
8
+ import io
9
+ import os
10
+ import re
11
+ import socket
12
+ import subprocess
13
+ import sys
14
+ import tempfile
15
+ import uuid
16
+ import zipfile
17
+ from io import StringIO
18
+ from pathlib import Path
19
+ from shutil import which
20
+ from typing import TYPE_CHECKING
21
+ from urllib.parse import urlparse
22
+
23
+ import httpx
24
+ import typer
25
+
26
+ from lfx.cli.script_loader import (
27
+ extract_structured_result,
28
+ find_graph_variable,
29
+ load_graph_from_script,
30
+ )
31
+ from lfx.load import load_flow_from_json
32
+ from lfx.schema.schema import InputValueRequest
33
+
34
+ if TYPE_CHECKING:
35
+ from types import ModuleType
36
+
37
+ # Attempt to import tomllib (3.11+) else fall back to tomli
38
+ _toml_parser: ModuleType | None = None
39
+ try:
40
+ import tomllib as _toml_parser
41
+ except ModuleNotFoundError:
42
+ with contextlib.suppress(ModuleNotFoundError):
43
+ import tomli as toml_parser
44
+
45
+ _toml_parser = toml_parser
46
+
47
+ MAX_PORT_NUMBER = 65535
48
+
49
+ # Fixed namespace constant for deterministic UUID5 generation across runs
50
+ _LANGFLOW_NAMESPACE_UUID = uuid.UUID("3c091057-e799-4e32-8ebc-27bc31e1108c")
51
+
52
+ # Environment variable for GitHub token
53
+ _GITHUB_TOKEN_ENV = "GITHUB_TOKEN"
54
+
55
+
56
+ def create_verbose_printer(*, verbose: bool):
57
+ """Create a verbose printer function that only prints in verbose mode.
58
+
59
+ Args:
60
+ verbose: Whether to print verbose output
61
+
62
+ Returns:
63
+ Function that prints to stderr only in verbose mode
64
+ """
65
+
66
+ def verbose_print(message: str) -> None:
67
+ """Print diagnostic messages to stderr only in verbose mode."""
68
+ if verbose:
69
+ typer.echo(message, file=sys.stderr)
70
+
71
+ return verbose_print
72
+
73
+
74
+ def is_port_in_use(port: int, host: str = "localhost") -> bool:
75
+ """Check if a port is already in use."""
76
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
77
+ try:
78
+ s.bind((host, port))
79
+ except OSError:
80
+ return True
81
+ else:
82
+ return False
83
+
84
+
85
+ def get_free_port(starting_port: int = 8000) -> int:
86
+ """Get a free port starting from the given port."""
87
+ port = starting_port
88
+ while port < MAX_PORT_NUMBER:
89
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
90
+ try:
91
+ s.bind(("", port))
92
+ except OSError:
93
+ port += 1
94
+ else:
95
+ return port
96
+ msg = "No free ports available"
97
+ raise RuntimeError(msg)
98
+
99
+
100
+ def get_best_access_host(host: str) -> str:
101
+ """Get the best host address for external access."""
102
+ # Note: 0.0.0.0 and :: are intentionally checked as they bind to all interfaces
103
+ if host in ("0.0.0.0", "::", ""):
104
+ return "localhost"
105
+ return host
106
+
107
+
108
+ def get_api_key() -> str:
109
+ """Get the API key from environment variable."""
110
+ api_key = os.getenv("LANGFLOW_API_KEY")
111
+ if not api_key:
112
+ msg = "LANGFLOW_API_KEY environment variable is not set"
113
+ raise ValueError(msg)
114
+ return api_key
115
+
116
+
117
+ def is_url(path_or_url: str) -> bool:
118
+ """Check if the given string is a URL.
119
+
120
+ Args:
121
+ path_or_url: String to check
122
+
123
+ Returns:
124
+ True if it's a URL, False otherwise
125
+ """
126
+ try:
127
+ result = urlparse(path_or_url)
128
+ return all([result.scheme, result.netloc])
129
+ except Exception: # noqa: BLE001
130
+ return False
131
+
132
+
133
+ def download_script_from_url(url: str, verbose_print) -> Path:
134
+ """Download a Python script from a URL and save it to a temporary file.
135
+
136
+ Args:
137
+ url: URL to download the script from
138
+ verbose_print: Function to print verbose messages
139
+
140
+ Returns:
141
+ Path to the temporary file containing the downloaded script
142
+
143
+ Raises:
144
+ typer.Exit: If download fails
145
+ """
146
+ verbose_print(f"Downloading script from URL: {url}")
147
+
148
+ try:
149
+ with httpx.Client(timeout=30.0) as client:
150
+ response = client.get(url)
151
+ response.raise_for_status()
152
+
153
+ # Check if the response is a Python script
154
+ content_type = response.headers.get("content-type", "").lower()
155
+ valid_types = {"application/x-python", "application/octet-stream"}
156
+ if not (content_type.startswith("text/") or content_type in valid_types):
157
+ verbose_print(f"Warning: Unexpected content type: {content_type}")
158
+
159
+ # Create a temporary file with .py extension
160
+ with tempfile.NamedTemporaryFile(mode="w", suffix=".py", delete=False) as temp_file:
161
+ temp_path = Path(temp_file.name)
162
+
163
+ # Write the content to the temporary file
164
+ script_content = response.text
165
+ temp_file.write(script_content)
166
+
167
+ verbose_print(f"✓ Script downloaded successfully to temporary file: {temp_path}")
168
+ return temp_path
169
+
170
+ except httpx.HTTPStatusError as e:
171
+ msg = f"✗ HTTP error downloading script: {e.response.status_code} - {e.response.text}"
172
+ verbose_print(msg)
173
+ raise typer.Exit(1) from e
174
+ except httpx.RequestError as e:
175
+ msg = f"✗ Network error downloading script: {e}"
176
+ verbose_print(msg)
177
+ raise typer.Exit(1) from e
178
+ except Exception as e:
179
+ msg = f"✗ Unexpected error downloading script: {e}"
180
+ verbose_print(msg)
181
+ raise typer.Exit(1) from e
182
+
183
+
184
+ def validate_script_path(script_path: Path | str, verbose_print) -> tuple[str, Path]:
185
+ """Validate script path or URL and return file extension and resolved path.
186
+
187
+ Args:
188
+ script_path: Path to the script file or URL
189
+ verbose_print: Function to print verbose messages
190
+
191
+ Returns:
192
+ Tuple of (file_extension, resolved_path)
193
+
194
+ Raises:
195
+ typer.Exit: If validation fails
196
+ """
197
+ # Handle URL case
198
+ if isinstance(script_path, str) and is_url(script_path):
199
+ resolved_path = download_script_from_url(script_path, verbose_print)
200
+ file_extension = resolved_path.suffix.lower()
201
+ if file_extension != ".py":
202
+ verbose_print(f"Error: URL must point to a Python script (.py file), got: {file_extension}")
203
+ raise typer.Exit(1)
204
+ return file_extension, resolved_path
205
+
206
+ # Handle local file case
207
+ if isinstance(script_path, str):
208
+ script_path = Path(script_path)
209
+
210
+ if not script_path.exists():
211
+ verbose_print(f"Error: File '{script_path}' does not exist.")
212
+ raise typer.Exit(1)
213
+
214
+ if not script_path.is_file():
215
+ verbose_print(f"Error: '{script_path}' is not a file.")
216
+ raise typer.Exit(1)
217
+
218
+ # Check file extension and validate
219
+ file_extension = script_path.suffix.lower()
220
+ if file_extension not in [".py", ".json"]:
221
+ verbose_print(f"Error: '{script_path}' must be a .py or .json file.")
222
+ raise typer.Exit(1)
223
+
224
+ return file_extension, script_path
225
+
226
+
227
+ def load_graph_from_path(script_path: Path, file_extension: str, verbose_print, *, verbose: bool = False):
228
+ """Load a graph from a Python script or JSON file.
229
+
230
+ Args:
231
+ script_path: Path to the script file
232
+ file_extension: File extension (.py or .json)
233
+ verbose_print: Function to print verbose messages
234
+ verbose: Whether verbose mode is enabled
235
+
236
+ Returns:
237
+ Loaded graph object
238
+
239
+ Raises:
240
+ typer.Exit: If loading fails
241
+ """
242
+ file_type = "Python script" if file_extension == ".py" else "JSON flow"
243
+ verbose_print(f"Analyzing {file_type}: {script_path}")
244
+
245
+ try:
246
+ if file_extension == ".py":
247
+ verbose_print("Analyzing Python script...")
248
+ graph_var = find_graph_variable(script_path)
249
+ if graph_var:
250
+ source_info = graph_var.get("source", "Unknown")
251
+ type_info = graph_var.get("type", "Unknown")
252
+ line_no = graph_var.get("line", "Unknown")
253
+ verbose_print(f"✓ Found 'graph' variable at line {line_no}")
254
+ verbose_print(f" Type: {type_info}")
255
+ verbose_print(f" Source: {source_info}")
256
+ else:
257
+ error_msg = "No 'graph' variable found in script"
258
+ verbose_print(f"✗ {error_msg}")
259
+ raise ValueError(error_msg)
260
+
261
+ verbose_print("Loading graph...")
262
+ graph = load_graph_from_script(script_path)
263
+ else: # .json
264
+ verbose_print("Loading JSON flow...")
265
+ graph = load_flow_from_json(script_path, disable_logs=not verbose)
266
+
267
+ except ValueError as e:
268
+ # Re-raise ValueError as typer.Exit to preserve the error message
269
+ raise typer.Exit(1) from e
270
+ except Exception as e:
271
+ verbose_print(f"✗ Failed to load graph: {e}")
272
+ raise typer.Exit(1) from e
273
+ else:
274
+ return graph
275
+
276
+
277
+ def prepare_graph(graph, verbose_print):
278
+ """Prepare a graph for execution.
279
+
280
+ Args:
281
+ graph: Graph object to prepare
282
+ verbose_print: Function to print verbose messages
283
+
284
+ Raises:
285
+ typer.Exit: If preparation fails
286
+ """
287
+ verbose_print("Preparing graph for execution...")
288
+ try:
289
+ graph.prepare()
290
+ verbose_print("✓ Graph prepared successfully")
291
+ except Exception as e:
292
+ verbose_print(f"✗ Failed to prepare graph: {e}")
293
+ raise typer.Exit(1) from e
294
+
295
+
296
+ async def execute_graph_with_capture(graph, input_value: str | None):
297
+ """Execute a graph and capture output.
298
+
299
+ Args:
300
+ graph: Graph object to execute
301
+ input_value: Input value to pass to the graph
302
+
303
+ Returns:
304
+ Tuple of (results, captured_logs)
305
+
306
+ Raises:
307
+ Exception: Re-raises any exception that occurs during graph execution
308
+ """
309
+ # Create input request
310
+ inputs = InputValueRequest(input_value=input_value) if input_value else None
311
+
312
+ # Capture output during execution
313
+ captured_stdout = StringIO()
314
+ captured_stderr = StringIO()
315
+
316
+ # Redirect stdout and stderr during graph execution
317
+ original_stdout = sys.stdout
318
+ original_stderr = sys.stderr
319
+
320
+ try:
321
+ sys.stdout = captured_stdout
322
+ sys.stderr = captured_stderr
323
+ results = [result async for result in graph.async_start(inputs)]
324
+ except Exception as exc:
325
+ # Capture any error output that was written to stderr
326
+ error_output = captured_stderr.getvalue()
327
+ if error_output:
328
+ # Add error output to the exception for better debugging
329
+ exc.args = (f"{exc.args[0] if exc.args else str(exc)}\n\nCaptured stderr:\n{error_output}",)
330
+ raise
331
+ finally:
332
+ # Restore original stdout/stderr
333
+ sys.stdout = original_stdout
334
+ sys.stderr = original_stderr
335
+
336
+ # Get captured logs
337
+ captured_logs = captured_stdout.getvalue() + captured_stderr.getvalue()
338
+
339
+ return results, captured_logs
340
+
341
+
342
+ def extract_result_data(results, captured_logs: str) -> dict:
343
+ """Extract structured result data from graph execution results.
344
+
345
+ Args:
346
+ results: Graph execution results
347
+ captured_logs: Captured output logs
348
+
349
+ Returns:
350
+ Structured result data dictionary
351
+ """
352
+ result_data = extract_structured_result(results)
353
+ result_data["logs"] = captured_logs
354
+ return result_data
355
+
356
+
357
+ # --- Dependency helpers ------------------------------------------------------------------
358
+
359
+
360
+ def _parse_pep723_block(script_path: Path, verbose_print) -> dict | None:
361
+ """Extract the TOML table contained in a PEP-723 inline metadata block.
362
+
363
+ Args:
364
+ script_path: Path to the Python script to inspect.
365
+ verbose_print: Diagnostic printer.
366
+
367
+ Returns:
368
+ Parsed TOML dict if a block is found and successfully parsed, otherwise None.
369
+ """
370
+ if _toml_parser is None:
371
+ verbose_print("tomllib/tomli not available - cannot parse inline dependencies")
372
+ return None
373
+
374
+ try:
375
+ lines = script_path.read_text(encoding="utf-8").splitlines()
376
+ except OSError as exc: # pragma: no cover
377
+ verbose_print(f"Failed reading script for dependency parsing: {exc}")
378
+ return None
379
+
380
+ # Locate `# /// script` and closing `# ///` markers.
381
+ try:
382
+ start_idx = next(i for i, ln in enumerate(lines) if ln.lstrip().startswith("# /// script")) + 1
383
+ end_idx = next(i for i, ln in enumerate(lines[start_idx:], start=start_idx) if ln.lstrip().startswith("# ///"))
384
+ except StopIteration:
385
+ return None # No valid block
386
+
387
+ # Remove leading comment markers and excess whitespace
388
+ block_lines: list[str] = []
389
+ for raw_line in lines[start_idx:end_idx]:
390
+ stripped_line = raw_line.lstrip()
391
+ if not stripped_line.startswith("#"):
392
+ continue
393
+ block_lines.append(stripped_line.lstrip("# "))
394
+
395
+ block_toml = "\n".join(block_lines).strip()
396
+ if not block_toml:
397
+ return None
398
+
399
+ try:
400
+ return _toml_parser.loads(block_toml)
401
+ except Exception as exc: # pragma: no cover # noqa: BLE001
402
+ verbose_print(f"Failed parsing TOML from PEP-723 block: {exc}")
403
+ return None
404
+
405
+
406
+ def extract_script_dependencies(script_path: Path, verbose_print) -> list[str]:
407
+ """Return dependency strings declared via PEP-723 inline metadata.
408
+
409
+ Only `.py` files are supported for now. Returns an empty list if the file has
410
+ no metadata block or could not be parsed.
411
+ """
412
+ if script_path.suffix != ".py":
413
+ return []
414
+
415
+ parsed = _parse_pep723_block(script_path, verbose_print)
416
+ if not parsed:
417
+ return []
418
+
419
+ deps = parsed.get("dependencies", [])
420
+ # Ensure list[str]
421
+ if isinstance(deps, list):
422
+ return [str(d).strip() for d in deps if str(d).strip()]
423
+ return []
424
+
425
+
426
+ def _needs_install(requirement: str) -> bool:
427
+ """Heuristic: check if *some* distribution that satisfies the requirement is present.
428
+
429
+ Exact version resolution is delegated to the installer; here we do a best-effort
430
+ importlib.metadata lookup for the top-level name before the first comparison op.
431
+ """
432
+ from packaging.requirements import Requirement # locally imported to avoid hard dep if unused
433
+
434
+ try:
435
+ req = Requirement(requirement)
436
+ except Exception: # noqa: BLE001
437
+ return True # If we cannot parse it, assume missing so installer handles it
438
+
439
+ try:
440
+ dist_version = importlib_metadata.version(req.name)
441
+ except importlib_metadata.PackageNotFoundError:
442
+ return True
443
+
444
+ # If specifier is empty, we already have it.
445
+ if not req.specifier:
446
+ return False
447
+
448
+ try:
449
+ from packaging.version import InvalidVersion, Version
450
+ except ImportError:
451
+ # If packaging is missing, we cannot compare - treat as missing.
452
+ return True
453
+
454
+ try:
455
+ if req.specifier.contains(Version(dist_version), prereleases=True):
456
+ return False
457
+ except InvalidVersion:
458
+ return True
459
+
460
+ return True
461
+
462
+
463
+ def ensure_dependencies_installed(dependencies: list[str], verbose_print) -> None:
464
+ """Install missing dependencies using uv (preferred) or pip.
465
+
466
+ Args:
467
+ dependencies: List of requirement strings (PEP 508 style).
468
+ verbose_print: Diagnostic printer.
469
+ """
470
+ if not dependencies:
471
+ return
472
+
473
+ missing = [req for req in dependencies if _needs_install(req)]
474
+ if not missing:
475
+ verbose_print("All script dependencies already satisfied")
476
+ return
477
+
478
+ installer_cmd: list[str]
479
+ if which("uv"):
480
+ installer_cmd = ["uv", "pip", "install", "--quiet", *missing]
481
+ tool_name = "uv"
482
+ else:
483
+ # Fall back to current interpreter's pip
484
+ installer_cmd = [sys.executable, "-m", "pip", "install", "--quiet", *missing]
485
+ tool_name = "pip"
486
+
487
+ verbose_print(f"Installing missing dependencies with {tool_name}: {', '.join(missing)}")
488
+ try:
489
+ subprocess.run(installer_cmd, check=True) # noqa: S603
490
+ verbose_print("✓ Dependency installation succeeded")
491
+ except subprocess.CalledProcessError as exc: # pragma: no cover
492
+ verbose_print(f"✗ Failed installing dependencies: {exc}")
493
+ raise typer.Exit(1) from exc
494
+
495
+
496
+ def flow_id_from_path(file_path: Path, root_dir: Path) -> str:
497
+ """Generate a deterministic UUID-5 based flow id from *file_path*.
498
+
499
+ The function uses a fixed namespace UUID and the POSIX-style relative path
500
+ (relative to *root_dir*) as the *name* when calling :pyfunc:`uuid.uuid5`.
501
+ This guarantees:
502
+
503
+ 1. The same folder deployed again produces identical flow IDs.
504
+ 2. IDs remain stable even if the absolute location of the folder changes
505
+ (only the relative path is hashed).
506
+ 3. Practically collision-free identifiers without maintaining external
507
+ state.
508
+
509
+ Args:
510
+ file_path: Path of the JSON flow file.
511
+ root_dir: Root directory from which *file_path* should be considered
512
+ relative. Typically the folder passed to the deploy command.
513
+
514
+ Returns:
515
+ -------
516
+ str
517
+ Canonical UUID string (36 chars, including hyphens).
518
+ """
519
+ relative = file_path.relative_to(root_dir).as_posix()
520
+ return str(uuid.uuid5(_LANGFLOW_NAMESPACE_UUID, relative))
521
+
522
+
523
+ # ---------------------------------------------------------------------------
524
+ # GitHub / ZIP repository helpers (synchronous equivalents of initial_setup)
525
+ # ---------------------------------------------------------------------------
526
+
527
+ _GITHUB_RE_REPO = re.compile(r"https?://(?:www\.)?github\.com/([\w.-]+)/([\w.-]+)(?:\.git)?/?$")
528
+ _GITHUB_RE_TREE = re.compile(r"https?://(?:www\.)?github\.com/([\w.-]+)/([\w.-]+)/tree/([\w\/-]+)")
529
+ _GITHUB_RE_RELEASE = re.compile(r"https?://(?:www\.)?github\.com/([\w.-]+)/([\w.-]+)/releases/tag/([\w\/-]+)")
530
+ _GITHUB_RE_COMMIT = re.compile(r"https?://(?:www\.)?github\.com/([\w.-]+)/([\w.-]+)/commit/(\w+)(?:/)?$")
531
+
532
+
533
+ def _github_headers() -> dict[str, str]:
534
+ token = os.getenv(_GITHUB_TOKEN_ENV)
535
+ if token:
536
+ return {"Authorization": f"token {token}"}
537
+ return {}
538
+
539
+
540
+ def detect_github_url_sync(url: str, *, timeout: float = 15.0) -> str:
541
+ """Convert various GitHub URLs into a direct `.zip` download link (sync).
542
+
543
+ Mirrors the async implementation in *initial_setup.setup.detect_github_url*.
544
+ """
545
+ if match := _GITHUB_RE_REPO.match(url):
546
+ owner, repo = match.groups()
547
+ # Determine default branch via GitHub API
548
+ with httpx.Client(timeout=timeout, follow_redirects=True, headers=_github_headers()) as client:
549
+ resp = client.get(f"https://api.github.com/repos/{owner}/{repo}")
550
+ resp.raise_for_status()
551
+ default_branch = resp.json().get("default_branch", "main")
552
+ return f"https://github.com/{owner}/{repo}/archive/refs/heads/{default_branch}.zip"
553
+
554
+ if match := _GITHUB_RE_TREE.match(url):
555
+ owner, repo, branch = match.groups()
556
+ branch = branch.rstrip("/")
557
+ return f"https://github.com/{owner}/{repo}/archive/refs/heads/{branch}.zip"
558
+
559
+ if match := _GITHUB_RE_RELEASE.match(url):
560
+ owner, repo, tag = match.groups()
561
+ tag = tag.rstrip("/")
562
+ return f"https://github.com/{owner}/{repo}/archive/refs/tags/{tag}.zip"
563
+
564
+ if match := _GITHUB_RE_COMMIT.match(url):
565
+ owner, repo, commit = match.groups()
566
+ return f"https://github.com/{owner}/{repo}/archive/{commit}.zip"
567
+
568
+ # Not a recognized GitHub URL; assume it's already a direct link
569
+ return url
570
+
571
+
572
+ def download_and_extract_repo(url: str, verbose_print, *, timeout: float = 60.0) -> Path:
573
+ """Download a ZIP archive from *url* and extract into a temp directory.
574
+
575
+ Returns the **root directory** containing the extracted files.
576
+ """
577
+ verbose_print(f"Downloading repository/ZIP from {url}")
578
+
579
+ zip_url = detect_github_url_sync(url)
580
+
581
+ try:
582
+ with httpx.Client(timeout=timeout, follow_redirects=True, headers=_github_headers()) as client:
583
+ resp = client.get(zip_url)
584
+ resp.raise_for_status()
585
+
586
+ tmp_dir = tempfile.TemporaryDirectory()
587
+ with zipfile.ZipFile(io.BytesIO(resp.content)) as zf:
588
+ zf.extractall(tmp_dir.name)
589
+
590
+ verbose_print(f"✓ Repository extracted to {tmp_dir.name}")
591
+
592
+ # Most GitHub archives have a single top-level folder; use it if present
593
+ root_path = Path(tmp_dir.name)
594
+ sub_entries = list(root_path.iterdir())
595
+ if len(sub_entries) == 1 and sub_entries[0].is_dir():
596
+ root_path = sub_entries[0]
597
+
598
+ # Ensure root on sys.path for custom components
599
+ if str(root_path) not in sys.path:
600
+ sys.path.insert(0, str(root_path))
601
+
602
+ # Attach TemporaryDirectory to path object so caller can keep reference
603
+ # and prevent premature cleanup. We set attribute _tmp_dir.
604
+ root_path._tmp_dir = tmp_dir # type: ignore[attr-defined] # noqa: SLF001
605
+
606
+ except httpx.HTTPStatusError as e:
607
+ verbose_print(f"✗ HTTP error downloading ZIP: {e.response.status_code}")
608
+ raise
609
+ except Exception as exc:
610
+ verbose_print(f"✗ Failed downloading or extracting repo: {exc}")
611
+ raise
612
+ else:
613
+ return root_path
614
+
615
+
616
+ def extract_script_docstring(script_path: Path) -> str | None:
617
+ """Extract the module-level docstring from a Python script.
618
+
619
+ Args:
620
+ script_path: Path to the Python script file
621
+
622
+ Returns:
623
+ The docstring text if found, None otherwise
624
+ """
625
+ try:
626
+ # Read the file content
627
+ with script_path.open(encoding="utf-8") as f:
628
+ content = f.read()
629
+
630
+ # Parse the AST
631
+ tree = ast.parse(content)
632
+
633
+ # Check if the first statement is a docstring
634
+ # A docstring is a string literal that appears as the first statement
635
+ if (
636
+ tree.body
637
+ and isinstance(tree.body[0], ast.Expr)
638
+ and isinstance(tree.body[0].value, ast.Constant)
639
+ and isinstance(tree.body[0].value.value, str)
640
+ ):
641
+ docstring = tree.body[0].value.value
642
+ # Clean up the docstring by removing extra whitespace
643
+ return docstring.strip()
644
+
645
+ except (OSError, SyntaxError, UnicodeDecodeError):
646
+ # If we can't read or parse the file, just return None
647
+ # Don't raise an error as this is optional functionality
648
+ pass
649
+
650
+ return None