lfx-nightly 0.2.0.dev25__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


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

Files changed (769) hide show
  1. lfx/__init__.py +0 -0
  2. lfx/__main__.py +25 -0
  3. lfx/_assets/component_index.json +1 -0
  4. lfx/base/__init__.py +0 -0
  5. lfx/base/agents/__init__.py +0 -0
  6. lfx/base/agents/agent.py +375 -0
  7. lfx/base/agents/altk_base_agent.py +380 -0
  8. lfx/base/agents/altk_tool_wrappers.py +565 -0
  9. lfx/base/agents/callback.py +130 -0
  10. lfx/base/agents/context.py +109 -0
  11. lfx/base/agents/crewai/__init__.py +0 -0
  12. lfx/base/agents/crewai/crew.py +231 -0
  13. lfx/base/agents/crewai/tasks.py +12 -0
  14. lfx/base/agents/default_prompts.py +23 -0
  15. lfx/base/agents/errors.py +15 -0
  16. lfx/base/agents/events.py +430 -0
  17. lfx/base/agents/utils.py +237 -0
  18. lfx/base/astra_assistants/__init__.py +0 -0
  19. lfx/base/astra_assistants/util.py +171 -0
  20. lfx/base/chains/__init__.py +0 -0
  21. lfx/base/chains/model.py +19 -0
  22. lfx/base/composio/__init__.py +0 -0
  23. lfx/base/composio/composio_base.py +2584 -0
  24. lfx/base/compressors/__init__.py +0 -0
  25. lfx/base/compressors/model.py +60 -0
  26. lfx/base/constants.py +46 -0
  27. lfx/base/curl/__init__.py +0 -0
  28. lfx/base/curl/parse.py +188 -0
  29. lfx/base/data/__init__.py +5 -0
  30. lfx/base/data/base_file.py +810 -0
  31. lfx/base/data/docling_utils.py +338 -0
  32. lfx/base/data/storage_utils.py +192 -0
  33. lfx/base/data/utils.py +362 -0
  34. lfx/base/datastax/__init__.py +5 -0
  35. lfx/base/datastax/astradb_base.py +896 -0
  36. lfx/base/document_transformers/__init__.py +0 -0
  37. lfx/base/document_transformers/model.py +43 -0
  38. lfx/base/embeddings/__init__.py +0 -0
  39. lfx/base/embeddings/aiml_embeddings.py +62 -0
  40. lfx/base/embeddings/embeddings_class.py +113 -0
  41. lfx/base/embeddings/model.py +26 -0
  42. lfx/base/flow_processing/__init__.py +0 -0
  43. lfx/base/flow_processing/utils.py +86 -0
  44. lfx/base/huggingface/__init__.py +0 -0
  45. lfx/base/huggingface/model_bridge.py +133 -0
  46. lfx/base/io/__init__.py +0 -0
  47. lfx/base/io/chat.py +21 -0
  48. lfx/base/io/text.py +22 -0
  49. lfx/base/knowledge_bases/__init__.py +3 -0
  50. lfx/base/knowledge_bases/knowledge_base_utils.py +137 -0
  51. lfx/base/langchain_utilities/__init__.py +0 -0
  52. lfx/base/langchain_utilities/model.py +35 -0
  53. lfx/base/langchain_utilities/spider_constants.py +1 -0
  54. lfx/base/langwatch/__init__.py +0 -0
  55. lfx/base/langwatch/utils.py +18 -0
  56. lfx/base/mcp/__init__.py +0 -0
  57. lfx/base/mcp/constants.py +2 -0
  58. lfx/base/mcp/util.py +1659 -0
  59. lfx/base/memory/__init__.py +0 -0
  60. lfx/base/memory/memory.py +49 -0
  61. lfx/base/memory/model.py +38 -0
  62. lfx/base/models/__init__.py +3 -0
  63. lfx/base/models/aiml_constants.py +51 -0
  64. lfx/base/models/anthropic_constants.py +51 -0
  65. lfx/base/models/aws_constants.py +151 -0
  66. lfx/base/models/chat_result.py +76 -0
  67. lfx/base/models/cometapi_constants.py +54 -0
  68. lfx/base/models/google_generative_ai_constants.py +70 -0
  69. lfx/base/models/google_generative_ai_model.py +38 -0
  70. lfx/base/models/groq_constants.py +150 -0
  71. lfx/base/models/groq_model_discovery.py +265 -0
  72. lfx/base/models/model.py +375 -0
  73. lfx/base/models/model_input_constants.py +378 -0
  74. lfx/base/models/model_metadata.py +41 -0
  75. lfx/base/models/model_utils.py +108 -0
  76. lfx/base/models/novita_constants.py +35 -0
  77. lfx/base/models/ollama_constants.py +52 -0
  78. lfx/base/models/openai_constants.py +129 -0
  79. lfx/base/models/sambanova_constants.py +18 -0
  80. lfx/base/models/watsonx_constants.py +36 -0
  81. lfx/base/processing/__init__.py +0 -0
  82. lfx/base/prompts/__init__.py +0 -0
  83. lfx/base/prompts/api_utils.py +224 -0
  84. lfx/base/prompts/utils.py +61 -0
  85. lfx/base/textsplitters/__init__.py +0 -0
  86. lfx/base/textsplitters/model.py +28 -0
  87. lfx/base/tools/__init__.py +0 -0
  88. lfx/base/tools/base.py +26 -0
  89. lfx/base/tools/component_tool.py +325 -0
  90. lfx/base/tools/constants.py +49 -0
  91. lfx/base/tools/flow_tool.py +132 -0
  92. lfx/base/tools/run_flow.py +698 -0
  93. lfx/base/vectorstores/__init__.py +0 -0
  94. lfx/base/vectorstores/model.py +193 -0
  95. lfx/base/vectorstores/utils.py +22 -0
  96. lfx/base/vectorstores/vector_store_connection_decorator.py +52 -0
  97. lfx/cli/__init__.py +5 -0
  98. lfx/cli/commands.py +327 -0
  99. lfx/cli/common.py +650 -0
  100. lfx/cli/run.py +506 -0
  101. lfx/cli/script_loader.py +289 -0
  102. lfx/cli/serve_app.py +546 -0
  103. lfx/cli/validation.py +69 -0
  104. lfx/components/FAISS/__init__.py +34 -0
  105. lfx/components/FAISS/faiss.py +111 -0
  106. lfx/components/Notion/__init__.py +19 -0
  107. lfx/components/Notion/add_content_to_page.py +269 -0
  108. lfx/components/Notion/create_page.py +94 -0
  109. lfx/components/Notion/list_database_properties.py +68 -0
  110. lfx/components/Notion/list_pages.py +122 -0
  111. lfx/components/Notion/list_users.py +77 -0
  112. lfx/components/Notion/page_content_viewer.py +93 -0
  113. lfx/components/Notion/search.py +111 -0
  114. lfx/components/Notion/update_page_property.py +114 -0
  115. lfx/components/__init__.py +428 -0
  116. lfx/components/_importing.py +42 -0
  117. lfx/components/agentql/__init__.py +3 -0
  118. lfx/components/agentql/agentql_api.py +151 -0
  119. lfx/components/aiml/__init__.py +37 -0
  120. lfx/components/aiml/aiml.py +115 -0
  121. lfx/components/aiml/aiml_embeddings.py +37 -0
  122. lfx/components/altk/__init__.py +34 -0
  123. lfx/components/altk/altk_agent.py +193 -0
  124. lfx/components/amazon/__init__.py +36 -0
  125. lfx/components/amazon/amazon_bedrock_converse.py +195 -0
  126. lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
  127. lfx/components/amazon/amazon_bedrock_model.py +130 -0
  128. lfx/components/amazon/s3_bucket_uploader.py +211 -0
  129. lfx/components/anthropic/__init__.py +34 -0
  130. lfx/components/anthropic/anthropic.py +187 -0
  131. lfx/components/apify/__init__.py +5 -0
  132. lfx/components/apify/apify_actor.py +325 -0
  133. lfx/components/arxiv/__init__.py +3 -0
  134. lfx/components/arxiv/arxiv.py +169 -0
  135. lfx/components/assemblyai/__init__.py +46 -0
  136. lfx/components/assemblyai/assemblyai_get_subtitles.py +83 -0
  137. lfx/components/assemblyai/assemblyai_lemur.py +183 -0
  138. lfx/components/assemblyai/assemblyai_list_transcripts.py +95 -0
  139. lfx/components/assemblyai/assemblyai_poll_transcript.py +72 -0
  140. lfx/components/assemblyai/assemblyai_start_transcript.py +188 -0
  141. lfx/components/azure/__init__.py +37 -0
  142. lfx/components/azure/azure_openai.py +95 -0
  143. lfx/components/azure/azure_openai_embeddings.py +83 -0
  144. lfx/components/baidu/__init__.py +32 -0
  145. lfx/components/baidu/baidu_qianfan_chat.py +113 -0
  146. lfx/components/bing/__init__.py +3 -0
  147. lfx/components/bing/bing_search_api.py +61 -0
  148. lfx/components/cassandra/__init__.py +40 -0
  149. lfx/components/cassandra/cassandra.py +264 -0
  150. lfx/components/cassandra/cassandra_chat.py +92 -0
  151. lfx/components/cassandra/cassandra_graph.py +238 -0
  152. lfx/components/chains/__init__.py +3 -0
  153. lfx/components/chroma/__init__.py +34 -0
  154. lfx/components/chroma/chroma.py +169 -0
  155. lfx/components/cleanlab/__init__.py +40 -0
  156. lfx/components/cleanlab/cleanlab_evaluator.py +155 -0
  157. lfx/components/cleanlab/cleanlab_rag_evaluator.py +254 -0
  158. lfx/components/cleanlab/cleanlab_remediator.py +131 -0
  159. lfx/components/clickhouse/__init__.py +34 -0
  160. lfx/components/clickhouse/clickhouse.py +135 -0
  161. lfx/components/cloudflare/__init__.py +32 -0
  162. lfx/components/cloudflare/cloudflare.py +81 -0
  163. lfx/components/cohere/__init__.py +40 -0
  164. lfx/components/cohere/cohere_embeddings.py +81 -0
  165. lfx/components/cohere/cohere_models.py +46 -0
  166. lfx/components/cohere/cohere_rerank.py +51 -0
  167. lfx/components/cometapi/__init__.py +32 -0
  168. lfx/components/cometapi/cometapi.py +166 -0
  169. lfx/components/composio/__init__.py +222 -0
  170. lfx/components/composio/agentql_composio.py +11 -0
  171. lfx/components/composio/agiled_composio.py +11 -0
  172. lfx/components/composio/airtable_composio.py +11 -0
  173. lfx/components/composio/apollo_composio.py +11 -0
  174. lfx/components/composio/asana_composio.py +11 -0
  175. lfx/components/composio/attio_composio.py +11 -0
  176. lfx/components/composio/bitbucket_composio.py +11 -0
  177. lfx/components/composio/bolna_composio.py +11 -0
  178. lfx/components/composio/brightdata_composio.py +11 -0
  179. lfx/components/composio/calendly_composio.py +11 -0
  180. lfx/components/composio/canva_composio.py +11 -0
  181. lfx/components/composio/canvas_composio.py +11 -0
  182. lfx/components/composio/coda_composio.py +11 -0
  183. lfx/components/composio/composio_api.py +278 -0
  184. lfx/components/composio/contentful_composio.py +11 -0
  185. lfx/components/composio/digicert_composio.py +11 -0
  186. lfx/components/composio/discord_composio.py +11 -0
  187. lfx/components/composio/dropbox_compnent.py +11 -0
  188. lfx/components/composio/elevenlabs_composio.py +11 -0
  189. lfx/components/composio/exa_composio.py +11 -0
  190. lfx/components/composio/figma_composio.py +11 -0
  191. lfx/components/composio/finage_composio.py +11 -0
  192. lfx/components/composio/firecrawl_composio.py +11 -0
  193. lfx/components/composio/fireflies_composio.py +11 -0
  194. lfx/components/composio/fixer_composio.py +11 -0
  195. lfx/components/composio/flexisign_composio.py +11 -0
  196. lfx/components/composio/freshdesk_composio.py +11 -0
  197. lfx/components/composio/github_composio.py +11 -0
  198. lfx/components/composio/gmail_composio.py +38 -0
  199. lfx/components/composio/googlebigquery_composio.py +11 -0
  200. lfx/components/composio/googlecalendar_composio.py +11 -0
  201. lfx/components/composio/googleclassroom_composio.py +11 -0
  202. lfx/components/composio/googledocs_composio.py +11 -0
  203. lfx/components/composio/googlemeet_composio.py +11 -0
  204. lfx/components/composio/googlesheets_composio.py +11 -0
  205. lfx/components/composio/googletasks_composio.py +8 -0
  206. lfx/components/composio/heygen_composio.py +11 -0
  207. lfx/components/composio/instagram_composio.py +11 -0
  208. lfx/components/composio/jira_composio.py +11 -0
  209. lfx/components/composio/jotform_composio.py +11 -0
  210. lfx/components/composio/klaviyo_composio.py +11 -0
  211. lfx/components/composio/linear_composio.py +11 -0
  212. lfx/components/composio/listennotes_composio.py +11 -0
  213. lfx/components/composio/mem0_composio.py +11 -0
  214. lfx/components/composio/miro_composio.py +11 -0
  215. lfx/components/composio/missive_composio.py +11 -0
  216. lfx/components/composio/notion_composio.py +11 -0
  217. lfx/components/composio/onedrive_composio.py +11 -0
  218. lfx/components/composio/outlook_composio.py +11 -0
  219. lfx/components/composio/pandadoc_composio.py +11 -0
  220. lfx/components/composio/peopledatalabs_composio.py +11 -0
  221. lfx/components/composio/perplexityai_composio.py +11 -0
  222. lfx/components/composio/reddit_composio.py +11 -0
  223. lfx/components/composio/serpapi_composio.py +11 -0
  224. lfx/components/composio/slack_composio.py +11 -0
  225. lfx/components/composio/slackbot_composio.py +11 -0
  226. lfx/components/composio/snowflake_composio.py +11 -0
  227. lfx/components/composio/supabase_composio.py +11 -0
  228. lfx/components/composio/tavily_composio.py +11 -0
  229. lfx/components/composio/timelinesai_composio.py +11 -0
  230. lfx/components/composio/todoist_composio.py +11 -0
  231. lfx/components/composio/wrike_composio.py +11 -0
  232. lfx/components/composio/youtube_composio.py +11 -0
  233. lfx/components/confluence/__init__.py +3 -0
  234. lfx/components/confluence/confluence.py +84 -0
  235. lfx/components/couchbase/__init__.py +34 -0
  236. lfx/components/couchbase/couchbase.py +102 -0
  237. lfx/components/crewai/__init__.py +49 -0
  238. lfx/components/crewai/crewai.py +108 -0
  239. lfx/components/crewai/hierarchical_crew.py +47 -0
  240. lfx/components/crewai/hierarchical_task.py +45 -0
  241. lfx/components/crewai/sequential_crew.py +53 -0
  242. lfx/components/crewai/sequential_task.py +74 -0
  243. lfx/components/crewai/sequential_task_agent.py +144 -0
  244. lfx/components/cuga/__init__.py +34 -0
  245. lfx/components/cuga/cuga_agent.py +730 -0
  246. lfx/components/custom_component/__init__.py +34 -0
  247. lfx/components/custom_component/custom_component.py +31 -0
  248. lfx/components/data/__init__.py +114 -0
  249. lfx/components/data_source/__init__.py +58 -0
  250. lfx/components/data_source/api_request.py +577 -0
  251. lfx/components/data_source/csv_to_data.py +101 -0
  252. lfx/components/data_source/json_to_data.py +106 -0
  253. lfx/components/data_source/mock_data.py +398 -0
  254. lfx/components/data_source/news_search.py +166 -0
  255. lfx/components/data_source/rss.py +71 -0
  256. lfx/components/data_source/sql_executor.py +101 -0
  257. lfx/components/data_source/url.py +311 -0
  258. lfx/components/data_source/web_search.py +326 -0
  259. lfx/components/datastax/__init__.py +76 -0
  260. lfx/components/datastax/astradb_assistant_manager.py +307 -0
  261. lfx/components/datastax/astradb_chatmemory.py +40 -0
  262. lfx/components/datastax/astradb_cql.py +288 -0
  263. lfx/components/datastax/astradb_graph.py +217 -0
  264. lfx/components/datastax/astradb_tool.py +378 -0
  265. lfx/components/datastax/astradb_vectorize.py +122 -0
  266. lfx/components/datastax/astradb_vectorstore.py +449 -0
  267. lfx/components/datastax/create_assistant.py +59 -0
  268. lfx/components/datastax/create_thread.py +33 -0
  269. lfx/components/datastax/dotenv.py +36 -0
  270. lfx/components/datastax/get_assistant.py +38 -0
  271. lfx/components/datastax/getenvvar.py +31 -0
  272. lfx/components/datastax/graph_rag.py +141 -0
  273. lfx/components/datastax/hcd.py +315 -0
  274. lfx/components/datastax/list_assistants.py +26 -0
  275. lfx/components/datastax/run.py +90 -0
  276. lfx/components/deactivated/__init__.py +15 -0
  277. lfx/components/deactivated/amazon_kendra.py +66 -0
  278. lfx/components/deactivated/chat_litellm_model.py +158 -0
  279. lfx/components/deactivated/code_block_extractor.py +26 -0
  280. lfx/components/deactivated/documents_to_data.py +22 -0
  281. lfx/components/deactivated/embed.py +16 -0
  282. lfx/components/deactivated/extract_key_from_data.py +46 -0
  283. lfx/components/deactivated/json_document_builder.py +57 -0
  284. lfx/components/deactivated/list_flows.py +20 -0
  285. lfx/components/deactivated/mcp_sse.py +61 -0
  286. lfx/components/deactivated/mcp_stdio.py +62 -0
  287. lfx/components/deactivated/merge_data.py +93 -0
  288. lfx/components/deactivated/message.py +37 -0
  289. lfx/components/deactivated/metal.py +54 -0
  290. lfx/components/deactivated/multi_query.py +59 -0
  291. lfx/components/deactivated/retriever.py +43 -0
  292. lfx/components/deactivated/selective_passthrough.py +77 -0
  293. lfx/components/deactivated/should_run_next.py +40 -0
  294. lfx/components/deactivated/split_text.py +63 -0
  295. lfx/components/deactivated/store_message.py +24 -0
  296. lfx/components/deactivated/sub_flow.py +124 -0
  297. lfx/components/deactivated/vectara_self_query.py +76 -0
  298. lfx/components/deactivated/vector_store.py +24 -0
  299. lfx/components/deepseek/__init__.py +34 -0
  300. lfx/components/deepseek/deepseek.py +136 -0
  301. lfx/components/docling/__init__.py +43 -0
  302. lfx/components/docling/chunk_docling_document.py +186 -0
  303. lfx/components/docling/docling_inline.py +238 -0
  304. lfx/components/docling/docling_remote.py +195 -0
  305. lfx/components/docling/export_docling_document.py +117 -0
  306. lfx/components/documentloaders/__init__.py +3 -0
  307. lfx/components/duckduckgo/__init__.py +3 -0
  308. lfx/components/duckduckgo/duck_duck_go_search_run.py +92 -0
  309. lfx/components/elastic/__init__.py +37 -0
  310. lfx/components/elastic/elasticsearch.py +267 -0
  311. lfx/components/elastic/opensearch.py +789 -0
  312. lfx/components/elastic/opensearch_multimodal.py +1575 -0
  313. lfx/components/embeddings/__init__.py +37 -0
  314. lfx/components/embeddings/similarity.py +77 -0
  315. lfx/components/embeddings/text_embedder.py +65 -0
  316. lfx/components/exa/__init__.py +3 -0
  317. lfx/components/exa/exa_search.py +68 -0
  318. lfx/components/files_and_knowledge/__init__.py +47 -0
  319. lfx/components/files_and_knowledge/directory.py +113 -0
  320. lfx/components/files_and_knowledge/file.py +841 -0
  321. lfx/components/files_and_knowledge/ingestion.py +694 -0
  322. lfx/components/files_and_knowledge/retrieval.py +264 -0
  323. lfx/components/files_and_knowledge/save_file.py +746 -0
  324. lfx/components/firecrawl/__init__.py +43 -0
  325. lfx/components/firecrawl/firecrawl_crawl_api.py +88 -0
  326. lfx/components/firecrawl/firecrawl_extract_api.py +136 -0
  327. lfx/components/firecrawl/firecrawl_map_api.py +89 -0
  328. lfx/components/firecrawl/firecrawl_scrape_api.py +73 -0
  329. lfx/components/flow_controls/__init__.py +58 -0
  330. lfx/components/flow_controls/conditional_router.py +208 -0
  331. lfx/components/flow_controls/data_conditional_router.py +126 -0
  332. lfx/components/flow_controls/flow_tool.py +111 -0
  333. lfx/components/flow_controls/listen.py +29 -0
  334. lfx/components/flow_controls/loop.py +163 -0
  335. lfx/components/flow_controls/notify.py +88 -0
  336. lfx/components/flow_controls/pass_message.py +36 -0
  337. lfx/components/flow_controls/run_flow.py +108 -0
  338. lfx/components/flow_controls/sub_flow.py +115 -0
  339. lfx/components/git/__init__.py +4 -0
  340. lfx/components/git/git.py +262 -0
  341. lfx/components/git/gitextractor.py +196 -0
  342. lfx/components/glean/__init__.py +3 -0
  343. lfx/components/glean/glean_search_api.py +173 -0
  344. lfx/components/google/__init__.py +17 -0
  345. lfx/components/google/gmail.py +193 -0
  346. lfx/components/google/google_bq_sql_executor.py +157 -0
  347. lfx/components/google/google_drive.py +92 -0
  348. lfx/components/google/google_drive_search.py +152 -0
  349. lfx/components/google/google_generative_ai.py +144 -0
  350. lfx/components/google/google_generative_ai_embeddings.py +141 -0
  351. lfx/components/google/google_oauth_token.py +89 -0
  352. lfx/components/google/google_search_api_core.py +68 -0
  353. lfx/components/google/google_serper_api_core.py +74 -0
  354. lfx/components/groq/__init__.py +34 -0
  355. lfx/components/groq/groq.py +143 -0
  356. lfx/components/helpers/__init__.py +154 -0
  357. lfx/components/homeassistant/__init__.py +7 -0
  358. lfx/components/homeassistant/home_assistant_control.py +152 -0
  359. lfx/components/homeassistant/list_home_assistant_states.py +137 -0
  360. lfx/components/huggingface/__init__.py +37 -0
  361. lfx/components/huggingface/huggingface.py +199 -0
  362. lfx/components/huggingface/huggingface_inference_api.py +106 -0
  363. lfx/components/ibm/__init__.py +34 -0
  364. lfx/components/ibm/watsonx.py +207 -0
  365. lfx/components/ibm/watsonx_embeddings.py +135 -0
  366. lfx/components/icosacomputing/__init__.py +5 -0
  367. lfx/components/icosacomputing/combinatorial_reasoner.py +84 -0
  368. lfx/components/input_output/__init__.py +40 -0
  369. lfx/components/input_output/chat.py +109 -0
  370. lfx/components/input_output/chat_output.py +184 -0
  371. lfx/components/input_output/text.py +27 -0
  372. lfx/components/input_output/text_output.py +29 -0
  373. lfx/components/input_output/webhook.py +56 -0
  374. lfx/components/jigsawstack/__init__.py +23 -0
  375. lfx/components/jigsawstack/ai_scrape.py +126 -0
  376. lfx/components/jigsawstack/ai_web_search.py +136 -0
  377. lfx/components/jigsawstack/file_read.py +115 -0
  378. lfx/components/jigsawstack/file_upload.py +94 -0
  379. lfx/components/jigsawstack/image_generation.py +205 -0
  380. lfx/components/jigsawstack/nsfw.py +60 -0
  381. lfx/components/jigsawstack/object_detection.py +124 -0
  382. lfx/components/jigsawstack/sentiment.py +112 -0
  383. lfx/components/jigsawstack/text_to_sql.py +90 -0
  384. lfx/components/jigsawstack/text_translate.py +77 -0
  385. lfx/components/jigsawstack/vocr.py +107 -0
  386. lfx/components/knowledge_bases/__init__.py +89 -0
  387. lfx/components/langchain_utilities/__init__.py +109 -0
  388. lfx/components/langchain_utilities/character.py +53 -0
  389. lfx/components/langchain_utilities/conversation.py +59 -0
  390. lfx/components/langchain_utilities/csv_agent.py +175 -0
  391. lfx/components/langchain_utilities/fake_embeddings.py +26 -0
  392. lfx/components/langchain_utilities/html_link_extractor.py +35 -0
  393. lfx/components/langchain_utilities/json_agent.py +100 -0
  394. lfx/components/langchain_utilities/langchain_hub.py +126 -0
  395. lfx/components/langchain_utilities/language_recursive.py +49 -0
  396. lfx/components/langchain_utilities/language_semantic.py +138 -0
  397. lfx/components/langchain_utilities/llm_checker.py +39 -0
  398. lfx/components/langchain_utilities/llm_math.py +42 -0
  399. lfx/components/langchain_utilities/natural_language.py +61 -0
  400. lfx/components/langchain_utilities/openai_tools.py +53 -0
  401. lfx/components/langchain_utilities/openapi.py +48 -0
  402. lfx/components/langchain_utilities/recursive_character.py +60 -0
  403. lfx/components/langchain_utilities/retrieval_qa.py +83 -0
  404. lfx/components/langchain_utilities/runnable_executor.py +137 -0
  405. lfx/components/langchain_utilities/self_query.py +80 -0
  406. lfx/components/langchain_utilities/spider.py +142 -0
  407. lfx/components/langchain_utilities/sql.py +40 -0
  408. lfx/components/langchain_utilities/sql_database.py +35 -0
  409. lfx/components/langchain_utilities/sql_generator.py +78 -0
  410. lfx/components/langchain_utilities/tool_calling.py +59 -0
  411. lfx/components/langchain_utilities/vector_store_info.py +49 -0
  412. lfx/components/langchain_utilities/vector_store_router.py +33 -0
  413. lfx/components/langchain_utilities/xml_agent.py +71 -0
  414. lfx/components/langwatch/__init__.py +3 -0
  415. lfx/components/langwatch/langwatch.py +278 -0
  416. lfx/components/link_extractors/__init__.py +3 -0
  417. lfx/components/llm_operations/__init__.py +46 -0
  418. lfx/components/llm_operations/batch_run.py +205 -0
  419. lfx/components/llm_operations/lambda_filter.py +218 -0
  420. lfx/components/llm_operations/llm_conditional_router.py +421 -0
  421. lfx/components/llm_operations/llm_selector.py +499 -0
  422. lfx/components/llm_operations/structured_output.py +244 -0
  423. lfx/components/lmstudio/__init__.py +34 -0
  424. lfx/components/lmstudio/lmstudioembeddings.py +89 -0
  425. lfx/components/lmstudio/lmstudiomodel.py +133 -0
  426. lfx/components/logic/__init__.py +181 -0
  427. lfx/components/maritalk/__init__.py +32 -0
  428. lfx/components/maritalk/maritalk.py +52 -0
  429. lfx/components/mem0/__init__.py +3 -0
  430. lfx/components/mem0/mem0_chat_memory.py +147 -0
  431. lfx/components/milvus/__init__.py +34 -0
  432. lfx/components/milvus/milvus.py +115 -0
  433. lfx/components/mistral/__init__.py +37 -0
  434. lfx/components/mistral/mistral.py +114 -0
  435. lfx/components/mistral/mistral_embeddings.py +58 -0
  436. lfx/components/models/__init__.py +89 -0
  437. lfx/components/models_and_agents/__init__.py +49 -0
  438. lfx/components/models_and_agents/agent.py +644 -0
  439. lfx/components/models_and_agents/embedding_model.py +423 -0
  440. lfx/components/models_and_agents/language_model.py +398 -0
  441. lfx/components/models_and_agents/mcp_component.py +594 -0
  442. lfx/components/models_and_agents/memory.py +268 -0
  443. lfx/components/models_and_agents/prompt.py +67 -0
  444. lfx/components/mongodb/__init__.py +34 -0
  445. lfx/components/mongodb/mongodb_atlas.py +213 -0
  446. lfx/components/needle/__init__.py +3 -0
  447. lfx/components/needle/needle.py +104 -0
  448. lfx/components/notdiamond/__init__.py +34 -0
  449. lfx/components/notdiamond/notdiamond.py +228 -0
  450. lfx/components/novita/__init__.py +32 -0
  451. lfx/components/novita/novita.py +130 -0
  452. lfx/components/nvidia/__init__.py +57 -0
  453. lfx/components/nvidia/nvidia.py +151 -0
  454. lfx/components/nvidia/nvidia_embedding.py +77 -0
  455. lfx/components/nvidia/nvidia_ingest.py +317 -0
  456. lfx/components/nvidia/nvidia_rerank.py +63 -0
  457. lfx/components/nvidia/system_assist.py +65 -0
  458. lfx/components/olivya/__init__.py +3 -0
  459. lfx/components/olivya/olivya.py +116 -0
  460. lfx/components/ollama/__init__.py +37 -0
  461. lfx/components/ollama/ollama.py +548 -0
  462. lfx/components/ollama/ollama_embeddings.py +103 -0
  463. lfx/components/openai/__init__.py +37 -0
  464. lfx/components/openai/openai.py +100 -0
  465. lfx/components/openai/openai_chat_model.py +176 -0
  466. lfx/components/openrouter/__init__.py +32 -0
  467. lfx/components/openrouter/openrouter.py +104 -0
  468. lfx/components/output_parsers/__init__.py +3 -0
  469. lfx/components/perplexity/__init__.py +34 -0
  470. lfx/components/perplexity/perplexity.py +75 -0
  471. lfx/components/pgvector/__init__.py +34 -0
  472. lfx/components/pgvector/pgvector.py +72 -0
  473. lfx/components/pinecone/__init__.py +34 -0
  474. lfx/components/pinecone/pinecone.py +134 -0
  475. lfx/components/processing/__init__.py +72 -0
  476. lfx/components/processing/alter_metadata.py +109 -0
  477. lfx/components/processing/combine_text.py +40 -0
  478. lfx/components/processing/converter.py +248 -0
  479. lfx/components/processing/create_data.py +111 -0
  480. lfx/components/processing/create_list.py +40 -0
  481. lfx/components/processing/data_operations.py +528 -0
  482. lfx/components/processing/data_to_dataframe.py +71 -0
  483. lfx/components/processing/dataframe_operations.py +313 -0
  484. lfx/components/processing/dataframe_to_toolset.py +259 -0
  485. lfx/components/processing/dynamic_create_data.py +357 -0
  486. lfx/components/processing/extract_key.py +54 -0
  487. lfx/components/processing/filter_data.py +43 -0
  488. lfx/components/processing/filter_data_values.py +89 -0
  489. lfx/components/processing/json_cleaner.py +104 -0
  490. lfx/components/processing/merge_data.py +91 -0
  491. lfx/components/processing/message_to_data.py +37 -0
  492. lfx/components/processing/output_parser.py +46 -0
  493. lfx/components/processing/parse_data.py +71 -0
  494. lfx/components/processing/parse_dataframe.py +69 -0
  495. lfx/components/processing/parse_json_data.py +91 -0
  496. lfx/components/processing/parser.py +148 -0
  497. lfx/components/processing/regex.py +83 -0
  498. lfx/components/processing/select_data.py +49 -0
  499. lfx/components/processing/split_text.py +141 -0
  500. lfx/components/processing/store_message.py +91 -0
  501. lfx/components/processing/update_data.py +161 -0
  502. lfx/components/prototypes/__init__.py +35 -0
  503. lfx/components/prototypes/python_function.py +73 -0
  504. lfx/components/qdrant/__init__.py +34 -0
  505. lfx/components/qdrant/qdrant.py +109 -0
  506. lfx/components/redis/__init__.py +37 -0
  507. lfx/components/redis/redis.py +89 -0
  508. lfx/components/redis/redis_chat.py +43 -0
  509. lfx/components/sambanova/__init__.py +32 -0
  510. lfx/components/sambanova/sambanova.py +84 -0
  511. lfx/components/scrapegraph/__init__.py +40 -0
  512. lfx/components/scrapegraph/scrapegraph_markdownify_api.py +64 -0
  513. lfx/components/scrapegraph/scrapegraph_search_api.py +64 -0
  514. lfx/components/scrapegraph/scrapegraph_smart_scraper_api.py +71 -0
  515. lfx/components/searchapi/__init__.py +34 -0
  516. lfx/components/searchapi/search.py +79 -0
  517. lfx/components/serpapi/__init__.py +3 -0
  518. lfx/components/serpapi/serp.py +115 -0
  519. lfx/components/supabase/__init__.py +34 -0
  520. lfx/components/supabase/supabase.py +76 -0
  521. lfx/components/tavily/__init__.py +4 -0
  522. lfx/components/tavily/tavily_extract.py +117 -0
  523. lfx/components/tavily/tavily_search.py +212 -0
  524. lfx/components/textsplitters/__init__.py +3 -0
  525. lfx/components/toolkits/__init__.py +3 -0
  526. lfx/components/tools/__init__.py +66 -0
  527. lfx/components/tools/calculator.py +109 -0
  528. lfx/components/tools/google_search_api.py +45 -0
  529. lfx/components/tools/google_serper_api.py +115 -0
  530. lfx/components/tools/python_code_structured_tool.py +328 -0
  531. lfx/components/tools/python_repl.py +98 -0
  532. lfx/components/tools/search_api.py +88 -0
  533. lfx/components/tools/searxng.py +145 -0
  534. lfx/components/tools/serp_api.py +120 -0
  535. lfx/components/tools/tavily_search_tool.py +345 -0
  536. lfx/components/tools/wikidata_api.py +103 -0
  537. lfx/components/tools/wikipedia_api.py +50 -0
  538. lfx/components/tools/yahoo_finance.py +130 -0
  539. lfx/components/twelvelabs/__init__.py +52 -0
  540. lfx/components/twelvelabs/convert_astra_results.py +84 -0
  541. lfx/components/twelvelabs/pegasus_index.py +311 -0
  542. lfx/components/twelvelabs/split_video.py +301 -0
  543. lfx/components/twelvelabs/text_embeddings.py +57 -0
  544. lfx/components/twelvelabs/twelvelabs_pegasus.py +408 -0
  545. lfx/components/twelvelabs/video_embeddings.py +100 -0
  546. lfx/components/twelvelabs/video_file.py +191 -0
  547. lfx/components/unstructured/__init__.py +3 -0
  548. lfx/components/unstructured/unstructured.py +121 -0
  549. lfx/components/upstash/__init__.py +34 -0
  550. lfx/components/upstash/upstash.py +124 -0
  551. lfx/components/utilities/__init__.py +43 -0
  552. lfx/components/utilities/calculator_core.py +89 -0
  553. lfx/components/utilities/current_date.py +42 -0
  554. lfx/components/utilities/id_generator.py +42 -0
  555. lfx/components/utilities/python_repl_core.py +98 -0
  556. lfx/components/vectara/__init__.py +37 -0
  557. lfx/components/vectara/vectara.py +97 -0
  558. lfx/components/vectara/vectara_rag.py +164 -0
  559. lfx/components/vectorstores/__init__.py +34 -0
  560. lfx/components/vectorstores/local_db.py +270 -0
  561. lfx/components/vertexai/__init__.py +37 -0
  562. lfx/components/vertexai/vertexai.py +71 -0
  563. lfx/components/vertexai/vertexai_embeddings.py +67 -0
  564. lfx/components/vlmrun/__init__.py +34 -0
  565. lfx/components/vlmrun/vlmrun_transcription.py +224 -0
  566. lfx/components/weaviate/__init__.py +34 -0
  567. lfx/components/weaviate/weaviate.py +89 -0
  568. lfx/components/wikipedia/__init__.py +4 -0
  569. lfx/components/wikipedia/wikidata.py +86 -0
  570. lfx/components/wikipedia/wikipedia.py +53 -0
  571. lfx/components/wolframalpha/__init__.py +3 -0
  572. lfx/components/wolframalpha/wolfram_alpha_api.py +54 -0
  573. lfx/components/xai/__init__.py +32 -0
  574. lfx/components/xai/xai.py +167 -0
  575. lfx/components/yahoosearch/__init__.py +3 -0
  576. lfx/components/yahoosearch/yahoo.py +137 -0
  577. lfx/components/youtube/__init__.py +52 -0
  578. lfx/components/youtube/channel.py +227 -0
  579. lfx/components/youtube/comments.py +231 -0
  580. lfx/components/youtube/playlist.py +33 -0
  581. lfx/components/youtube/search.py +120 -0
  582. lfx/components/youtube/trending.py +285 -0
  583. lfx/components/youtube/video_details.py +263 -0
  584. lfx/components/youtube/youtube_transcripts.py +206 -0
  585. lfx/components/zep/__init__.py +3 -0
  586. lfx/components/zep/zep.py +45 -0
  587. lfx/constants.py +6 -0
  588. lfx/custom/__init__.py +7 -0
  589. lfx/custom/attributes.py +87 -0
  590. lfx/custom/code_parser/__init__.py +3 -0
  591. lfx/custom/code_parser/code_parser.py +361 -0
  592. lfx/custom/custom_component/__init__.py +0 -0
  593. lfx/custom/custom_component/base_component.py +128 -0
  594. lfx/custom/custom_component/component.py +1890 -0
  595. lfx/custom/custom_component/component_with_cache.py +8 -0
  596. lfx/custom/custom_component/custom_component.py +650 -0
  597. lfx/custom/dependency_analyzer.py +165 -0
  598. lfx/custom/directory_reader/__init__.py +3 -0
  599. lfx/custom/directory_reader/directory_reader.py +359 -0
  600. lfx/custom/directory_reader/utils.py +171 -0
  601. lfx/custom/eval.py +12 -0
  602. lfx/custom/schema.py +32 -0
  603. lfx/custom/tree_visitor.py +21 -0
  604. lfx/custom/utils.py +877 -0
  605. lfx/custom/validate.py +523 -0
  606. lfx/events/__init__.py +1 -0
  607. lfx/events/event_manager.py +110 -0
  608. lfx/exceptions/__init__.py +0 -0
  609. lfx/exceptions/component.py +15 -0
  610. lfx/field_typing/__init__.py +91 -0
  611. lfx/field_typing/constants.py +216 -0
  612. lfx/field_typing/range_spec.py +35 -0
  613. lfx/graph/__init__.py +6 -0
  614. lfx/graph/edge/__init__.py +0 -0
  615. lfx/graph/edge/base.py +300 -0
  616. lfx/graph/edge/schema.py +119 -0
  617. lfx/graph/edge/utils.py +0 -0
  618. lfx/graph/graph/__init__.py +0 -0
  619. lfx/graph/graph/ascii.py +202 -0
  620. lfx/graph/graph/base.py +2298 -0
  621. lfx/graph/graph/constants.py +63 -0
  622. lfx/graph/graph/runnable_vertices_manager.py +133 -0
  623. lfx/graph/graph/schema.py +53 -0
  624. lfx/graph/graph/state_model.py +66 -0
  625. lfx/graph/graph/utils.py +1024 -0
  626. lfx/graph/schema.py +75 -0
  627. lfx/graph/state/__init__.py +0 -0
  628. lfx/graph/state/model.py +250 -0
  629. lfx/graph/utils.py +206 -0
  630. lfx/graph/vertex/__init__.py +0 -0
  631. lfx/graph/vertex/base.py +826 -0
  632. lfx/graph/vertex/constants.py +0 -0
  633. lfx/graph/vertex/exceptions.py +4 -0
  634. lfx/graph/vertex/param_handler.py +316 -0
  635. lfx/graph/vertex/schema.py +26 -0
  636. lfx/graph/vertex/utils.py +19 -0
  637. lfx/graph/vertex/vertex_types.py +489 -0
  638. lfx/helpers/__init__.py +141 -0
  639. lfx/helpers/base_model.py +71 -0
  640. lfx/helpers/custom.py +13 -0
  641. lfx/helpers/data.py +167 -0
  642. lfx/helpers/flow.py +308 -0
  643. lfx/inputs/__init__.py +68 -0
  644. lfx/inputs/constants.py +2 -0
  645. lfx/inputs/input_mixin.py +352 -0
  646. lfx/inputs/inputs.py +718 -0
  647. lfx/inputs/validators.py +19 -0
  648. lfx/interface/__init__.py +6 -0
  649. lfx/interface/components.py +897 -0
  650. lfx/interface/importing/__init__.py +5 -0
  651. lfx/interface/importing/utils.py +39 -0
  652. lfx/interface/initialize/__init__.py +3 -0
  653. lfx/interface/initialize/loading.py +317 -0
  654. lfx/interface/listing.py +26 -0
  655. lfx/interface/run.py +16 -0
  656. lfx/interface/utils.py +111 -0
  657. lfx/io/__init__.py +63 -0
  658. lfx/io/schema.py +295 -0
  659. lfx/load/__init__.py +8 -0
  660. lfx/load/load.py +256 -0
  661. lfx/load/utils.py +99 -0
  662. lfx/log/__init__.py +5 -0
  663. lfx/log/logger.py +411 -0
  664. lfx/logging/__init__.py +11 -0
  665. lfx/logging/logger.py +24 -0
  666. lfx/memory/__init__.py +70 -0
  667. lfx/memory/stubs.py +302 -0
  668. lfx/processing/__init__.py +1 -0
  669. lfx/processing/process.py +238 -0
  670. lfx/processing/utils.py +25 -0
  671. lfx/py.typed +0 -0
  672. lfx/schema/__init__.py +66 -0
  673. lfx/schema/artifact.py +83 -0
  674. lfx/schema/content_block.py +62 -0
  675. lfx/schema/content_types.py +91 -0
  676. lfx/schema/cross_module.py +80 -0
  677. lfx/schema/data.py +309 -0
  678. lfx/schema/dataframe.py +210 -0
  679. lfx/schema/dotdict.py +74 -0
  680. lfx/schema/encoders.py +13 -0
  681. lfx/schema/graph.py +47 -0
  682. lfx/schema/image.py +184 -0
  683. lfx/schema/json_schema.py +186 -0
  684. lfx/schema/log.py +62 -0
  685. lfx/schema/message.py +493 -0
  686. lfx/schema/openai_responses_schemas.py +74 -0
  687. lfx/schema/properties.py +41 -0
  688. lfx/schema/schema.py +180 -0
  689. lfx/schema/serialize.py +13 -0
  690. lfx/schema/table.py +142 -0
  691. lfx/schema/validators.py +114 -0
  692. lfx/serialization/__init__.py +5 -0
  693. lfx/serialization/constants.py +2 -0
  694. lfx/serialization/serialization.py +314 -0
  695. lfx/services/__init__.py +26 -0
  696. lfx/services/base.py +28 -0
  697. lfx/services/cache/__init__.py +6 -0
  698. lfx/services/cache/base.py +183 -0
  699. lfx/services/cache/service.py +166 -0
  700. lfx/services/cache/utils.py +169 -0
  701. lfx/services/chat/__init__.py +1 -0
  702. lfx/services/chat/config.py +2 -0
  703. lfx/services/chat/schema.py +10 -0
  704. lfx/services/database/__init__.py +5 -0
  705. lfx/services/database/service.py +25 -0
  706. lfx/services/deps.py +194 -0
  707. lfx/services/factory.py +19 -0
  708. lfx/services/initialize.py +19 -0
  709. lfx/services/interfaces.py +103 -0
  710. lfx/services/manager.py +185 -0
  711. lfx/services/mcp_composer/__init__.py +6 -0
  712. lfx/services/mcp_composer/factory.py +16 -0
  713. lfx/services/mcp_composer/service.py +1441 -0
  714. lfx/services/schema.py +21 -0
  715. lfx/services/session.py +87 -0
  716. lfx/services/settings/__init__.py +3 -0
  717. lfx/services/settings/auth.py +133 -0
  718. lfx/services/settings/base.py +668 -0
  719. lfx/services/settings/constants.py +43 -0
  720. lfx/services/settings/factory.py +23 -0
  721. lfx/services/settings/feature_flags.py +11 -0
  722. lfx/services/settings/service.py +35 -0
  723. lfx/services/settings/utils.py +40 -0
  724. lfx/services/shared_component_cache/__init__.py +1 -0
  725. lfx/services/shared_component_cache/factory.py +30 -0
  726. lfx/services/shared_component_cache/service.py +9 -0
  727. lfx/services/storage/__init__.py +5 -0
  728. lfx/services/storage/local.py +185 -0
  729. lfx/services/storage/service.py +177 -0
  730. lfx/services/tracing/__init__.py +1 -0
  731. lfx/services/tracing/service.py +21 -0
  732. lfx/settings.py +6 -0
  733. lfx/template/__init__.py +6 -0
  734. lfx/template/field/__init__.py +0 -0
  735. lfx/template/field/base.py +260 -0
  736. lfx/template/field/prompt.py +15 -0
  737. lfx/template/frontend_node/__init__.py +6 -0
  738. lfx/template/frontend_node/base.py +214 -0
  739. lfx/template/frontend_node/constants.py +65 -0
  740. lfx/template/frontend_node/custom_components.py +79 -0
  741. lfx/template/template/__init__.py +0 -0
  742. lfx/template/template/base.py +100 -0
  743. lfx/template/utils.py +217 -0
  744. lfx/type_extraction/__init__.py +19 -0
  745. lfx/type_extraction/type_extraction.py +75 -0
  746. lfx/type_extraction.py +80 -0
  747. lfx/utils/__init__.py +1 -0
  748. lfx/utils/async_helpers.py +42 -0
  749. lfx/utils/component_utils.py +154 -0
  750. lfx/utils/concurrency.py +60 -0
  751. lfx/utils/connection_string_parser.py +11 -0
  752. lfx/utils/constants.py +233 -0
  753. lfx/utils/data_structure.py +212 -0
  754. lfx/utils/exceptions.py +22 -0
  755. lfx/utils/helpers.py +34 -0
  756. lfx/utils/image.py +79 -0
  757. lfx/utils/langflow_utils.py +52 -0
  758. lfx/utils/lazy_load.py +15 -0
  759. lfx/utils/request_utils.py +18 -0
  760. lfx/utils/schemas.py +139 -0
  761. lfx/utils/ssrf_protection.py +384 -0
  762. lfx/utils/util.py +626 -0
  763. lfx/utils/util_strings.py +56 -0
  764. lfx/utils/validate_cloud.py +26 -0
  765. lfx/utils/version.py +24 -0
  766. lfx_nightly-0.2.0.dev25.dist-info/METADATA +312 -0
  767. lfx_nightly-0.2.0.dev25.dist-info/RECORD +769 -0
  768. lfx_nightly-0.2.0.dev25.dist-info/WHEEL +4 -0
  769. lfx_nightly-0.2.0.dev25.dist-info/entry_points.txt +2 -0
@@ -0,0 +1,698 @@
1
+ from collections import Counter
2
+ from datetime import datetime
3
+ from types import MethodType # near the imports
4
+ from typing import TYPE_CHECKING, Any
5
+
6
+ from langflow.helpers.flow import get_flow_by_id_or_name
7
+ from langflow.processing.process import process_tweaks_on_graph
8
+
9
+ from lfx.base.tools.constants import TOOL_OUTPUT_NAME
10
+ from lfx.custom.custom_component.component import Component, get_component_toolkit
11
+ from lfx.field_typing import Tool
12
+ from lfx.graph.graph.base import Graph
13
+ from lfx.graph.vertex.base import Vertex
14
+
15
+ # TODO: switch to lfx
16
+ from lfx.helpers import get_flow_inputs, run_flow
17
+ from lfx.inputs.inputs import BoolInput, DropdownInput, InputTypes, MessageTextInput, StrInput
18
+ from lfx.log.logger import logger
19
+ from lfx.schema.data import Data
20
+ from lfx.schema.dotdict import dotdict
21
+ from lfx.services.cache.utils import CacheMiss
22
+ from lfx.services.deps import get_shared_component_cache_service
23
+ from lfx.template.field.base import Output
24
+
25
+ if TYPE_CHECKING:
26
+ from collections.abc import Callable
27
+
28
+ from lfx.base.tools.component_tool import ComponentToolkit
29
+
30
+
31
+ class RunFlowBaseComponent(Component):
32
+ def __init__(self, *args, **kwargs):
33
+ self._flow_output_methods: set[str] = set()
34
+ super().__init__(*args, **kwargs)
35
+ self.add_tool_output = True
36
+ ################################################################
37
+ # cache the selected flow's graph in the shared component cache
38
+ # if cache_flow is enabled.
39
+ ################################################################
40
+ self._shared_component_cache = get_shared_component_cache_service()
41
+ # add all the flow cache related methods to the dispatcher.
42
+ # these are used internally among the cache related methods.
43
+ # the _flow_cache_call method is meant to be user-facing
44
+ # for cache operations as it handles validation.
45
+ self._cache_flow_dispatcher: dict[str, Callable[..., Any]] = {
46
+ "get": self._get_cached_flow,
47
+ "set": self._set_cached_flow,
48
+ "delete": self._delete_cached_flow,
49
+ "_build_key": self._build_flow_cache_key,
50
+ "_build_graph": self._build_graph_from_dict,
51
+ }
52
+ # save the run's outputs to avoid re-executing
53
+ # the flow if it has multiple outputs.
54
+ self._last_run_outputs: list[Data] | None = None
55
+ # save the updated_at of the user's selected flow
56
+ self._cached_flow_updated_at: str | None = None
57
+
58
+ _base_inputs: list[InputTypes] = [
59
+ DropdownInput(
60
+ name="flow_name_selected",
61
+ display_name="Flow Name",
62
+ info="The name of the flow to run.",
63
+ options=[],
64
+ options_metadata=[],
65
+ real_time_refresh=True,
66
+ refresh_button=True,
67
+ value=None,
68
+ ),
69
+ StrInput(
70
+ name="flow_id_selected",
71
+ display_name="Flow ID",
72
+ info="The ID of the flow to run.",
73
+ value=None,
74
+ show=False,
75
+ override_skip=True, # persist to runtime
76
+ ),
77
+ MessageTextInput(
78
+ name="session_id",
79
+ display_name="Session ID",
80
+ info="The session ID to run the flow in.",
81
+ advanced=True,
82
+ ),
83
+ # bool dropdown to select if the flow should be cached
84
+ # Note: the user's selected flow is automatically updated when
85
+ # when the flow_name_selected dropdown is refreshed.
86
+ # TODO: find a more explicit way to update the cached flow.
87
+ BoolInput(
88
+ name="cache_flow",
89
+ display_name="Cache Flow",
90
+ info="Whether to cache the selected flow.",
91
+ value=False,
92
+ advanced=True,
93
+ ),
94
+ ]
95
+ _base_outputs: list[Output] = []
96
+ default_keys = ["code", "_type", "flow_name_selected", "flow_id_selected", "session_id", "cache_flow"]
97
+ FLOW_INPUTS: list[dotdict] = []
98
+ flow_tweak_data: dict = {}
99
+ IOPUT_SEP = "~" # separator for joining a vertex id and input/output name to form a unique input/output name
100
+
101
+ ################################################################
102
+ # set and register the selected flow's output methods
103
+ ################################################################
104
+ def map_outputs(self) -> None: # Note: overrides the base map_outputs method
105
+ super().map_outputs()
106
+ self._ensure_flow_output_methods()
107
+
108
+ def _ensure_flow_output_methods(self) -> None:
109
+ self._clear_dynamic_flow_output_methods()
110
+ for output in self._outputs_map.values():
111
+ if not output or not output.name or output.name == TOOL_OUTPUT_NAME or self.IOPUT_SEP not in output.name:
112
+ continue
113
+ vertex_id, output_name = output.name.split(self.IOPUT_SEP, 1)
114
+ output.method = self._register_flow_output_method(
115
+ vertex_id=vertex_id,
116
+ output_name=output_name,
117
+ )
118
+
119
+ ################################################################
120
+ # Flow retrieval
121
+ ################################################################
122
+ async def get_flow(self, flow_name_selected: str | None = None, flow_id_selected: str | None = None) -> Data:
123
+ """Get a flow's data by name or id."""
124
+ flow = await get_flow_by_id_or_name(
125
+ user_id=self.user_id,
126
+ flow_id=flow_id_selected,
127
+ flow_name=flow_name_selected,
128
+ )
129
+ return flow or Data(data={})
130
+
131
+ async def get_graph(
132
+ self,
133
+ flow_name_selected: str | None = None,
134
+ flow_id_selected: str | None = None,
135
+ updated_at: str | None = None,
136
+ ) -> Graph | None:
137
+ """Get a flow's graph by name or id."""
138
+ if not (flow_name_selected or flow_id_selected):
139
+ msg = "Flow name or id is required"
140
+ raise ValueError(msg)
141
+ if flow_id_selected and (flow := self._flow_cache_call("get", flow_id=flow_id_selected)):
142
+ if self._is_cached_flow_up_to_date(flow, updated_at):
143
+ return flow
144
+ self._flow_cache_call("delete", flow_id=flow_id_selected) # stale, delete it
145
+
146
+ # TODO: use flow id only
147
+ flow = await self.get_flow(flow_name_selected=flow_name_selected, flow_id_selected=flow_id_selected)
148
+ if not flow:
149
+ msg = "Flow not found"
150
+ raise ValueError(msg)
151
+
152
+ graph = Graph.from_payload(
153
+ payload=flow.data.get("data", {}),
154
+ flow_id=flow_id_selected,
155
+ flow_name=flow_name_selected,
156
+ )
157
+ graph.description = flow.data.get("description", None)
158
+ graph.updated_at = flow.data.get("updated_at", None)
159
+
160
+ self._flow_cache_call("set", flow=graph)
161
+
162
+ return graph
163
+
164
+ ################################################################
165
+ # Flow inputs/config
166
+ ################################################################
167
+ def get_new_fields_from_graph(self, graph: Graph) -> list[dotdict]:
168
+ inputs = get_flow_inputs(graph)
169
+ return self.get_new_fields(inputs)
170
+
171
+ def update_build_config_from_graph(self, build_config: dotdict, graph: Graph):
172
+ try:
173
+ new_fields = self.get_new_fields_from_graph(graph)
174
+ keep_fields: set[str] = set([new_field["name"] for new_field in new_fields] + self.default_keys)
175
+ self.delete_fields(build_config, [key for key in build_config if key not in keep_fields])
176
+ build_config.update((field["name"], field) for field in new_fields)
177
+ except Exception as e:
178
+ msg = "Error updating build config from graph"
179
+ logger.exception(msg)
180
+ raise RuntimeError(msg) from e
181
+
182
+ def get_new_fields(self, inputs_vertex: list[Vertex]) -> list[dotdict]:
183
+ new_fields: list[dotdict] = []
184
+ vdisp_cts = Counter(v.display_name for v in inputs_vertex)
185
+
186
+ for vertex in inputs_vertex:
187
+ field_template = vertex.data.get("node", {}).get("template", {})
188
+ field_order = vertex.data.get("node", {}).get("field_order", [])
189
+ if not (field_order and field_template):
190
+ continue
191
+ new_vertex_inputs = [
192
+ dotdict(
193
+ {
194
+ **field_template[input_name],
195
+ "name": self._get_ioput_name(vertex.id, input_name),
196
+ "display_name": (
197
+ f"{field_template[input_name]['display_name']} ({vertex.display_name})"
198
+ if vdisp_cts[vertex.display_name] == 1
199
+ else (
200
+ f"{field_template[input_name]['display_name']}"
201
+ f"({vertex.display_name}-{vertex.id.split('-')[-1]})"
202
+ )
203
+ ),
204
+ # TODO: make this more robust?
205
+ "tool_mode": not (field_template[input_name].get("advanced", False)),
206
+ }
207
+ )
208
+ for input_name in field_order
209
+ if input_name in field_template
210
+ ]
211
+ new_fields += new_vertex_inputs
212
+ return new_fields
213
+
214
+ def add_new_fields(self, build_config: dotdict, new_fields: list[dotdict]) -> dotdict:
215
+ """Add new fields to the build_config."""
216
+ for field in new_fields:
217
+ build_config[field["name"]] = field
218
+ return build_config
219
+
220
+ def delete_fields(self, build_config: dotdict, fields: dict | list[str]) -> None:
221
+ """Delete specified fields from build_config.
222
+
223
+ Args:
224
+ build_config: The build_config to delete the fields from.
225
+ fields: The fields to delete from the build_config.
226
+ """
227
+ if isinstance(fields, dict):
228
+ fields = list(fields.keys())
229
+ for field in fields:
230
+ build_config.pop(field, None)
231
+
232
+ async def get_required_data(self) -> tuple[str, list[dotdict]] | None:
233
+ """Retrieve flow description and tool-mode input fields for the selected flow.
234
+
235
+ Fetches the graph for the given flow, extracts its input fields, and filters
236
+ for only those inputs that are eligible for tool mode (non-advanced fields).
237
+
238
+ Args:
239
+ flow_name_selected: The name of the flow to retrieve data for. If None,
240
+ returns None.
241
+
242
+ Returns:
243
+ A tuple of (flow_description, tool_mode_fields) where:
244
+ - flow_description (str): The human-readable description of the flow
245
+ - tool_mode_fields (list[dotdict]): Input fields marked for tool mode
246
+ Returns None if the flow cannot be found or loaded.
247
+ """
248
+ graph = await self.get_graph(self.flow_name_selected, self.flow_id_selected, self._cached_flow_updated_at)
249
+ formatted_outputs = self._format_flow_outputs(graph)
250
+ self._sync_flow_outputs(formatted_outputs)
251
+ new_fields = self.get_new_fields_from_graph(graph)
252
+ new_fields = self.update_input_types(new_fields)
253
+
254
+ return (graph.description, [field for field in new_fields if field.get("tool_mode") is True])
255
+
256
+ def update_input_types(self, fields: list[dotdict]) -> list[dotdict]:
257
+ """Update the input_types of the fields.
258
+
259
+ If a field's input_types is None, it will be set to an empty list.
260
+
261
+ Args:
262
+ fields: The fields to update the input_types for.
263
+
264
+ Returns:
265
+ The updated fields.
266
+ """
267
+ for field in fields:
268
+ if isinstance(field, dict):
269
+ if field.get("input_types", None) is None:
270
+ field["input_types"] = []
271
+ elif hasattr(field, "input_types") and field.input_types is None:
272
+ field.input_types = []
273
+ return fields
274
+
275
+ async def _get_tools(self) -> list[Tool]:
276
+ """Expose flow as a tool."""
277
+ component_toolkit: type[ComponentToolkit] = get_component_toolkit()
278
+ flow_description, tool_mode_inputs = await self.get_required_data()
279
+ if not tool_mode_inputs:
280
+ return []
281
+ # convert list of dicts to list of dotdicts
282
+ tool_mode_inputs = [dotdict(field) for field in tool_mode_inputs]
283
+ return component_toolkit(component=self).get_tools(
284
+ tool_name=f"{self.flow_name_selected}_tool",
285
+ tool_description=(
286
+ f"Tool designed to execute the flow '{self.flow_name_selected}'. Flow details: {flow_description}."
287
+ ),
288
+ callbacks=self.get_langchain_callbacks(),
289
+ flow_mode_inputs=tool_mode_inputs,
290
+ )
291
+
292
+ ################################################################
293
+ # Flow output resolution
294
+ ################################################################
295
+ async def _get_cached_run_outputs(
296
+ self,
297
+ *,
298
+ user_id: str | None = None,
299
+ tweaks: dict | None,
300
+ inputs: dict | list[dict] | None,
301
+ output_type: str,
302
+ ):
303
+ if self._last_run_outputs is not None:
304
+ return self._last_run_outputs
305
+ resolved_tweaks = tweaks or self.flow_tweak_data or {}
306
+ resolved_inputs = (inputs or self._flow_run_inputs or self._build_inputs_from_tweaks(resolved_tweaks)) or None
307
+ self._last_run_outputs = await self._run_flow_with_cached_graph(
308
+ user_id=user_id,
309
+ tweaks=resolved_tweaks,
310
+ inputs=resolved_inputs,
311
+ output_type=output_type,
312
+ )
313
+ return self._last_run_outputs
314
+
315
+ async def _resolve_flow_output(self, *, vertex_id: str, output_name: str):
316
+ """Resolve the value of a given vertex's output.
317
+
318
+ Given a vertex_id and output_name, it will resolve the value of the output
319
+ belonging to the vertex with the given vertex_id.
320
+
321
+ Args:
322
+ vertex_id: The ID of the vertex to resolve the output for.
323
+ output_name: The name of the output to resolve.
324
+
325
+ Returns:
326
+ The resolved output.
327
+ """
328
+ run_outputs = await self._get_cached_run_outputs(
329
+ user_id=self.user_id,
330
+ tweaks=self.flow_tweak_data,
331
+ inputs=None,
332
+ output_type="any",
333
+ )
334
+
335
+ if not run_outputs:
336
+ return None
337
+ first_output = run_outputs[0]
338
+ if not first_output.outputs:
339
+ return None
340
+ for result in first_output.outputs:
341
+ if not (result and result.component_id == vertex_id):
342
+ continue
343
+ if isinstance(result.results, dict) and output_name in result.results:
344
+ return result.results[output_name]
345
+ if result.artifacts and output_name in result.artifacts:
346
+ return result.artifacts[output_name]
347
+ return result.results or result.artifacts or result.outputs
348
+
349
+ return None
350
+
351
+ def _clear_dynamic_flow_output_methods(self) -> None:
352
+ for method_name in self._flow_output_methods:
353
+ if hasattr(self, method_name):
354
+ delattr(self, method_name)
355
+ self._flow_output_methods.clear()
356
+
357
+ def _register_flow_output_method(self, *, vertex_id: str, output_name: str) -> str:
358
+ safe_vertex = vertex_id.replace("-", "_")
359
+ safe_output = output_name.replace("-", "_").replace(self.IOPUT_SEP, "_")
360
+ method_name = f"_resolve_flow_output__{safe_vertex}__{safe_output}"
361
+
362
+ async def _dynamic_resolver(_self):
363
+ return await _self._resolve_flow_output( # noqa: SLF001
364
+ vertex_id=vertex_id,
365
+ output_name=output_name,
366
+ )
367
+
368
+ setattr(self, method_name, MethodType(_dynamic_resolver, self))
369
+ self._flow_output_methods.add(method_name)
370
+ return method_name
371
+
372
+ ################################################################
373
+ # Dynamic flow output synchronization
374
+ ################################################################
375
+ def _sync_flow_outputs(self, outputs: list[Output]) -> None:
376
+ """Persist dynamic flow outputs in the component.
377
+
378
+ Args:
379
+ outputs: The list of Output objects to persist.
380
+
381
+ Returns:
382
+ None
383
+ """
384
+ tool_output = None
385
+ if TOOL_OUTPUT_NAME in self._outputs_map:
386
+ tool_output = self._outputs_map[TOOL_OUTPUT_NAME]
387
+ else:
388
+ tool_output = next(
389
+ (out for out in outputs if out and out.name == TOOL_OUTPUT_NAME),
390
+ None,
391
+ )
392
+
393
+ self.outputs = outputs
394
+ self._outputs_map = {out.name: out for out in outputs if out}
395
+ self._outputs_map[TOOL_OUTPUT_NAME] = tool_output
396
+
397
+ async def update_outputs(self, frontend_node: dict, field_name: str, field_value: Any) -> dict:
398
+ """Update the outputs of the frontend node.
399
+
400
+ This method is called when the flow_name_selected field is updated.
401
+ It will generate the Output objects for the selected flow and update the outputs of the frontend node.
402
+
403
+ Args:
404
+ frontend_node: The frontend node to update the outputs for.
405
+ field_name: The name of the field that was updated.
406
+ field_value: The value of the field that was updated.
407
+
408
+ Returns:
409
+ The updated frontend node.
410
+ """
411
+ if field_name != "flow_name_selected" or not field_value:
412
+ return frontend_node
413
+
414
+ flow_selected_metadata = (
415
+ frontend_node.get("template", {}).get("flow_name_selected", {}).get("selected_metadata", {})
416
+ )
417
+ graph = await self.get_graph(
418
+ flow_name_selected=field_value,
419
+ flow_id_selected=flow_selected_metadata.get("id"),
420
+ updated_at=flow_selected_metadata.get("updated_at"),
421
+ )
422
+ outputs = self._format_flow_outputs(graph) # generate Output objects from the flow's output nodes
423
+ self._sync_flow_outputs(outputs)
424
+ frontend_node["outputs"] = [output.model_dump() for output in outputs]
425
+ return frontend_node
426
+
427
+ ################################################################
428
+ # Tool mode + formatting
429
+ ################################################################
430
+ def _format_flow_outputs(self, graph: Graph) -> list[Output]:
431
+ """Generate Output objects from the graph's outputs.
432
+
433
+ The Output objects modify the name and method of the graph's outputs.
434
+ The name is modified by prepending the vertex_id and to the original name,
435
+ which uniquely identifies the output.
436
+ The method is set to a dynamically generated method which uses a unique name
437
+ to resolve the output to its value generated during the flow execution.
438
+
439
+ Args:
440
+ graph: The graph to generate outputs for.
441
+
442
+ Returns:
443
+ A list of Output objects.
444
+ """
445
+ output_vertices: list[Vertex] = [v for v in graph.vertices if v.is_output]
446
+ outputs: list[Output] = []
447
+ vdisp_cts = Counter(v.display_name for v in output_vertices)
448
+ for vertex in output_vertices:
449
+ one_out = len(vertex.outputs) == 1
450
+ for vertex_output in vertex.outputs:
451
+ new_name = self._get_ioput_name(vertex.id, vertex_output.get("name"))
452
+ output = Output(**vertex_output)
453
+ output.name = new_name
454
+ output.method = self._register_flow_output_method(
455
+ vertex_id=vertex.id,
456
+ output_name=vertex_output.get("name"),
457
+ )
458
+ vdn = vertex.display_name
459
+ odn = output.display_name
460
+ output.display_name = (
461
+ vdn
462
+ if one_out and vdisp_cts[vdn] == 1
463
+ else odn
464
+ + (
465
+ # output.display_name potentially collides w/ those of other vertices
466
+ f" ({vdn})"
467
+ if vdisp_cts[vdn] == 1
468
+ # output.display_name collides w/ those of duplicate vertices
469
+ else f"-{vertex.id}"
470
+ )
471
+ )
472
+ outputs.append(output)
473
+
474
+ return outputs
475
+
476
+ def _get_ioput_name(
477
+ self,
478
+ vertex_id: str,
479
+ ioput_name: str,
480
+ ) -> str:
481
+ """Helper for joining a vertex id and input/output name to form a unique input/output name.
482
+
483
+ Args:
484
+ vertex_id: The ID of the vertex who's input/output name is being generated.
485
+ ioput_name: The name of the input/output to get the name for.
486
+
487
+ Returns:
488
+ A unique output name for the given vertex's output.
489
+ """
490
+ if not vertex_id or not ioput_name:
491
+ msg = "Vertex ID and input/output name are required"
492
+ raise ValueError(msg)
493
+ return f"{vertex_id}{self.IOPUT_SEP}{ioput_name}"
494
+
495
+ ################################################################
496
+ # Flow execution
497
+ ################################################################
498
+ async def _run_flow_with_cached_graph(
499
+ self,
500
+ *,
501
+ user_id: str | None = None,
502
+ tweaks: dict | None = None,
503
+ inputs: dict | list[dict] | None = None,
504
+ output_type: str = "any", # "any" is used to return all outputs
505
+ ):
506
+ graph = await self.get_graph(
507
+ flow_name_selected=self.flow_name_selected,
508
+ flow_id_selected=self.flow_id_selected,
509
+ updated_at=self._cached_flow_updated_at,
510
+ )
511
+ if tweaks:
512
+ graph = process_tweaks_on_graph(graph, tweaks)
513
+
514
+ return await run_flow(
515
+ inputs=inputs,
516
+ flow_id=self.flow_id_selected,
517
+ flow_name=self.flow_name_selected,
518
+ user_id=user_id,
519
+ session_id=self.session_id,
520
+ output_type=output_type,
521
+ graph=graph,
522
+ )
523
+
524
+ ################################################################
525
+ # Flow cache utils
526
+ ################################################################
527
+ def _flow_cache_call(self, action: str, *args, **kwargs):
528
+ """Call a flow cache related method."""
529
+ if not self.cache_flow:
530
+ msg = "Cache flow is disabled"
531
+ logger.warning(msg)
532
+ return None
533
+ if self._shared_component_cache is None:
534
+ logger.warning("Shared component cache is not available")
535
+ return None
536
+
537
+ handler = self._cache_flow_dispatcher.get(action)
538
+ if handler is None:
539
+ msg = f"Unknown cache action: {action}"
540
+ raise ValueError(msg)
541
+ try:
542
+ return handler(*args, **kwargs)
543
+ except Exception as exc: # noqa: BLE001
544
+ key = kwargs.get("cache_key") or kwargs.get("flow_name") or kwargs.get("flow_name_selected")
545
+ if not key and args:
546
+ key = args[0]
547
+ logger.warning("Cache %s failed for key %s: %s", action, key or "[missing key]", exc)
548
+ return None
549
+
550
+ def _get_cached_flow(self, *, flow_id: str | None = None) -> Graph | None:
551
+ cache_key = self._build_flow_cache_key(flow_id=flow_id)
552
+ cache_entry = self._shared_component_cache.get(cache_key)
553
+ if isinstance(cache_entry, CacheMiss):
554
+ logger.debug(f"{cache_entry} for key {cache_key}")
555
+ return None
556
+ if not cache_entry:
557
+ logger.warning(f"None or empty cache entry ({cache_entry}) for key {cache_key}")
558
+ return None
559
+ return self._build_graph_from_dict(cache_entry=cache_entry)
560
+
561
+ def _set_cached_flow(self, *, flow: Graph) -> None:
562
+ graph_dump = flow.dump()
563
+ payload = {
564
+ "graph_dump": graph_dump,
565
+ "flow_id": flow.flow_id,
566
+ "user_id": self.user_id,
567
+ "description": flow.description or graph_dump.get("description"),
568
+ "updated_at": flow.updated_at or graph_dump.get("updated_at"),
569
+ }
570
+ cache_key = self._build_flow_cache_key(flow_id=flow.flow_id)
571
+ self._shared_component_cache.set(cache_key, payload)
572
+
573
+ def _build_flow_cache_key(self, *, flow_id: str | None = None) -> str | None:
574
+ """Build a cache key for a flow.
575
+
576
+ Raises a ValueError if the user or flow ID is not provided.
577
+
578
+ Args:
579
+ flow_id: The ID of the flow to build the cache key for.
580
+
581
+ Returns:
582
+ The cache key for the flow.
583
+ """
584
+ if not (self.user_id and flow_id):
585
+ msg = "Failed to build cache key: Flow ID and user ID are required"
586
+ raise ValueError(msg)
587
+ return f"run_flow:{self.user_id}:{flow_id or 'missing_id'}"
588
+
589
+ def _build_graph_from_dict(self, *, cache_entry: dict[str, Any]) -> Graph | None:
590
+ if not (graph_dump := cache_entry.get("graph_dump")):
591
+ return None
592
+ graph = Graph.from_payload(
593
+ payload=graph_dump.get("data", {}),
594
+ flow_id=cache_entry.get("flow_id"),
595
+ flow_name=cache_entry.get("flow_name"),
596
+ user_id=cache_entry.get("user_id"),
597
+ )
598
+ graph.description = cache_entry.get("description") or graph_dump.get("description")
599
+ graph.updated_at = cache_entry.get("updated_at") or graph_dump.get("updated_at")
600
+ return graph
601
+
602
+ def _is_cached_flow_up_to_date(self, cached_flow: Graph, updated_at: str | None) -> bool:
603
+ if not updated_at or not (cached_ts := getattr(cached_flow, "updated_at", None)):
604
+ return False # both timetamps must be present
605
+ return self._parse_timestamp(cached_ts) >= self._parse_timestamp(updated_at)
606
+
607
+ @staticmethod
608
+ def _parse_timestamp(value: str | None) -> datetime | None:
609
+ from datetime import timezone
610
+
611
+ if not value:
612
+ return None
613
+ try:
614
+ dt = datetime.fromisoformat(value.replace("Z", "+00:00"))
615
+ return dt.replace(tzinfo=timezone.utc, microsecond=0)
616
+ except ValueError:
617
+ logger.warning("Invalid updated_at value: %s", value)
618
+ return None
619
+
620
+ def _delete_cached_flow(self, flow_id: str | None) -> None:
621
+ """Remove the flow with the given ID or name from cache.
622
+
623
+ Args:
624
+ flow_id: The ID of the flow to delete from cache.
625
+ flow_name: The name of the flow to delete from cache.
626
+
627
+ Returns:
628
+ None
629
+ """
630
+ err_msg_prefix = "Failed to delete user flow from cache"
631
+ if self._shared_component_cache is None:
632
+ msg = f"{err_msg_prefix}: Shared component cache is not available"
633
+ raise ValueError(msg)
634
+ if not self.user_id:
635
+ msg = f"{err_msg_prefix}: Please provide your user ID"
636
+ raise ValueError(msg)
637
+ if not flow_id or not flow_id.strip():
638
+ msg = f"{err_msg_prefix}: Please provide a valid flow ID"
639
+ raise ValueError(msg)
640
+
641
+ self._shared_component_cache.delete(self._build_flow_cache_key(flow_id=flow_id))
642
+
643
+ ################################################################
644
+ # Build inputs and flow tweak data
645
+ ################################################################
646
+ def _extract_tweaks_from_keyed_values(
647
+ self,
648
+ values: dict[str, Any] | None,
649
+ ) -> dict[str, dict[str, Any]]:
650
+ tweaks: dict[str, dict[str, Any]] = {}
651
+ if not values:
652
+ return tweaks
653
+ for field_name, field_value in values.items():
654
+ if self.IOPUT_SEP not in field_name:
655
+ continue
656
+ node_id, param_name = field_name.split(self.IOPUT_SEP, 1)
657
+ tweaks.setdefault(node_id, {})[param_name] = field_value
658
+ return tweaks
659
+
660
+ def _build_inputs_from_tweaks(
661
+ self,
662
+ tweaks: dict[str, dict[str, Any]],
663
+ ) -> list[dict[str, Any]]:
664
+ inputs: list[dict[str, Any]] = []
665
+ for vertex_id, params in tweaks.items():
666
+ if "input_value" not in params:
667
+ continue
668
+ payload: dict[str, Any] = {
669
+ "components": [vertex_id],
670
+ "input_value": params["input_value"],
671
+ }
672
+ if params.get("type"):
673
+ payload["type"] = params["type"]
674
+ inputs.append(payload)
675
+ return inputs
676
+
677
+ def _get_selected_flow_updated_at(self) -> str | None:
678
+ updated_at = (
679
+ getattr(self, "_vertex", {})
680
+ .data.get("node", {})
681
+ .get("template", {})
682
+ .get("flow_name_selected", {})
683
+ .get("selected_metadata", {})
684
+ .get("updated_at", None)
685
+ )
686
+ if updated_at:
687
+ return updated_at
688
+ return self._attributes.get("flow_name_selected_updated_at")
689
+
690
+ def _pre_run_setup(self) -> None: # Note: overrides the base pre_run_setup method
691
+ """Reset the last run's outputs upon new flow execution."""
692
+ self._last_run_outputs = None
693
+ self._cached_flow_updated_at = self._get_selected_flow_updated_at()
694
+ if self._cached_flow_updated_at:
695
+ self._attributes["flow_name_selected_updated_at"] = self._cached_flow_updated_at
696
+ self._attributes["flow_tweak_data"] = {}
697
+ self.flow_tweak_data = self._extract_tweaks_from_keyed_values(self._attributes)
698
+ self._flow_run_inputs = self._build_inputs_from_tweaks(self.flow_tweak_data)
File without changes