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.
- lfx/__init__.py +0 -0
- lfx/__main__.py +25 -0
- lfx/_assets/component_index.json +1 -0
- lfx/base/__init__.py +0 -0
- lfx/base/agents/__init__.py +0 -0
- lfx/base/agents/agent.py +375 -0
- lfx/base/agents/altk_base_agent.py +380 -0
- lfx/base/agents/altk_tool_wrappers.py +565 -0
- lfx/base/agents/callback.py +130 -0
- lfx/base/agents/context.py +109 -0
- lfx/base/agents/crewai/__init__.py +0 -0
- lfx/base/agents/crewai/crew.py +231 -0
- lfx/base/agents/crewai/tasks.py +12 -0
- lfx/base/agents/default_prompts.py +23 -0
- lfx/base/agents/errors.py +15 -0
- lfx/base/agents/events.py +430 -0
- lfx/base/agents/utils.py +237 -0
- lfx/base/astra_assistants/__init__.py +0 -0
- lfx/base/astra_assistants/util.py +171 -0
- lfx/base/chains/__init__.py +0 -0
- lfx/base/chains/model.py +19 -0
- lfx/base/composio/__init__.py +0 -0
- lfx/base/composio/composio_base.py +2584 -0
- lfx/base/compressors/__init__.py +0 -0
- lfx/base/compressors/model.py +60 -0
- lfx/base/constants.py +46 -0
- lfx/base/curl/__init__.py +0 -0
- lfx/base/curl/parse.py +188 -0
- lfx/base/data/__init__.py +5 -0
- lfx/base/data/base_file.py +810 -0
- lfx/base/data/docling_utils.py +338 -0
- lfx/base/data/storage_utils.py +192 -0
- lfx/base/data/utils.py +362 -0
- lfx/base/datastax/__init__.py +5 -0
- lfx/base/datastax/astradb_base.py +896 -0
- lfx/base/document_transformers/__init__.py +0 -0
- lfx/base/document_transformers/model.py +43 -0
- lfx/base/embeddings/__init__.py +0 -0
- lfx/base/embeddings/aiml_embeddings.py +62 -0
- lfx/base/embeddings/embeddings_class.py +113 -0
- lfx/base/embeddings/model.py +26 -0
- lfx/base/flow_processing/__init__.py +0 -0
- lfx/base/flow_processing/utils.py +86 -0
- lfx/base/huggingface/__init__.py +0 -0
- lfx/base/huggingface/model_bridge.py +133 -0
- lfx/base/io/__init__.py +0 -0
- lfx/base/io/chat.py +21 -0
- lfx/base/io/text.py +22 -0
- lfx/base/knowledge_bases/__init__.py +3 -0
- lfx/base/knowledge_bases/knowledge_base_utils.py +137 -0
- lfx/base/langchain_utilities/__init__.py +0 -0
- lfx/base/langchain_utilities/model.py +35 -0
- lfx/base/langchain_utilities/spider_constants.py +1 -0
- lfx/base/langwatch/__init__.py +0 -0
- lfx/base/langwatch/utils.py +18 -0
- lfx/base/mcp/__init__.py +0 -0
- lfx/base/mcp/constants.py +2 -0
- lfx/base/mcp/util.py +1659 -0
- lfx/base/memory/__init__.py +0 -0
- lfx/base/memory/memory.py +49 -0
- lfx/base/memory/model.py +38 -0
- lfx/base/models/__init__.py +3 -0
- lfx/base/models/aiml_constants.py +51 -0
- lfx/base/models/anthropic_constants.py +51 -0
- lfx/base/models/aws_constants.py +151 -0
- lfx/base/models/chat_result.py +76 -0
- lfx/base/models/cometapi_constants.py +54 -0
- lfx/base/models/google_generative_ai_constants.py +70 -0
- lfx/base/models/google_generative_ai_model.py +38 -0
- lfx/base/models/groq_constants.py +150 -0
- lfx/base/models/groq_model_discovery.py +265 -0
- lfx/base/models/model.py +375 -0
- lfx/base/models/model_input_constants.py +378 -0
- lfx/base/models/model_metadata.py +41 -0
- lfx/base/models/model_utils.py +108 -0
- lfx/base/models/novita_constants.py +35 -0
- lfx/base/models/ollama_constants.py +52 -0
- lfx/base/models/openai_constants.py +129 -0
- lfx/base/models/sambanova_constants.py +18 -0
- lfx/base/models/watsonx_constants.py +36 -0
- lfx/base/processing/__init__.py +0 -0
- lfx/base/prompts/__init__.py +0 -0
- lfx/base/prompts/api_utils.py +224 -0
- lfx/base/prompts/utils.py +61 -0
- lfx/base/textsplitters/__init__.py +0 -0
- lfx/base/textsplitters/model.py +28 -0
- lfx/base/tools/__init__.py +0 -0
- lfx/base/tools/base.py +26 -0
- lfx/base/tools/component_tool.py +325 -0
- lfx/base/tools/constants.py +49 -0
- lfx/base/tools/flow_tool.py +132 -0
- lfx/base/tools/run_flow.py +698 -0
- lfx/base/vectorstores/__init__.py +0 -0
- lfx/base/vectorstores/model.py +193 -0
- lfx/base/vectorstores/utils.py +22 -0
- lfx/base/vectorstores/vector_store_connection_decorator.py +52 -0
- lfx/cli/__init__.py +5 -0
- lfx/cli/commands.py +327 -0
- lfx/cli/common.py +650 -0
- lfx/cli/run.py +506 -0
- lfx/cli/script_loader.py +289 -0
- lfx/cli/serve_app.py +546 -0
- lfx/cli/validation.py +69 -0
- lfx/components/FAISS/__init__.py +34 -0
- lfx/components/FAISS/faiss.py +111 -0
- lfx/components/Notion/__init__.py +19 -0
- lfx/components/Notion/add_content_to_page.py +269 -0
- lfx/components/Notion/create_page.py +94 -0
- lfx/components/Notion/list_database_properties.py +68 -0
- lfx/components/Notion/list_pages.py +122 -0
- lfx/components/Notion/list_users.py +77 -0
- lfx/components/Notion/page_content_viewer.py +93 -0
- lfx/components/Notion/search.py +111 -0
- lfx/components/Notion/update_page_property.py +114 -0
- lfx/components/__init__.py +428 -0
- lfx/components/_importing.py +42 -0
- lfx/components/agentql/__init__.py +3 -0
- lfx/components/agentql/agentql_api.py +151 -0
- lfx/components/aiml/__init__.py +37 -0
- lfx/components/aiml/aiml.py +115 -0
- lfx/components/aiml/aiml_embeddings.py +37 -0
- lfx/components/altk/__init__.py +34 -0
- lfx/components/altk/altk_agent.py +193 -0
- lfx/components/amazon/__init__.py +36 -0
- lfx/components/amazon/amazon_bedrock_converse.py +195 -0
- lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
- lfx/components/amazon/amazon_bedrock_model.py +130 -0
- lfx/components/amazon/s3_bucket_uploader.py +211 -0
- lfx/components/anthropic/__init__.py +34 -0
- lfx/components/anthropic/anthropic.py +187 -0
- lfx/components/apify/__init__.py +5 -0
- lfx/components/apify/apify_actor.py +325 -0
- lfx/components/arxiv/__init__.py +3 -0
- lfx/components/arxiv/arxiv.py +169 -0
- lfx/components/assemblyai/__init__.py +46 -0
- lfx/components/assemblyai/assemblyai_get_subtitles.py +83 -0
- lfx/components/assemblyai/assemblyai_lemur.py +183 -0
- lfx/components/assemblyai/assemblyai_list_transcripts.py +95 -0
- lfx/components/assemblyai/assemblyai_poll_transcript.py +72 -0
- lfx/components/assemblyai/assemblyai_start_transcript.py +188 -0
- lfx/components/azure/__init__.py +37 -0
- lfx/components/azure/azure_openai.py +95 -0
- lfx/components/azure/azure_openai_embeddings.py +83 -0
- lfx/components/baidu/__init__.py +32 -0
- lfx/components/baidu/baidu_qianfan_chat.py +113 -0
- lfx/components/bing/__init__.py +3 -0
- lfx/components/bing/bing_search_api.py +61 -0
- lfx/components/cassandra/__init__.py +40 -0
- lfx/components/cassandra/cassandra.py +264 -0
- lfx/components/cassandra/cassandra_chat.py +92 -0
- lfx/components/cassandra/cassandra_graph.py +238 -0
- lfx/components/chains/__init__.py +3 -0
- lfx/components/chroma/__init__.py +34 -0
- lfx/components/chroma/chroma.py +169 -0
- lfx/components/cleanlab/__init__.py +40 -0
- lfx/components/cleanlab/cleanlab_evaluator.py +155 -0
- lfx/components/cleanlab/cleanlab_rag_evaluator.py +254 -0
- lfx/components/cleanlab/cleanlab_remediator.py +131 -0
- lfx/components/clickhouse/__init__.py +34 -0
- lfx/components/clickhouse/clickhouse.py +135 -0
- lfx/components/cloudflare/__init__.py +32 -0
- lfx/components/cloudflare/cloudflare.py +81 -0
- lfx/components/cohere/__init__.py +40 -0
- lfx/components/cohere/cohere_embeddings.py +81 -0
- lfx/components/cohere/cohere_models.py +46 -0
- lfx/components/cohere/cohere_rerank.py +51 -0
- lfx/components/cometapi/__init__.py +32 -0
- lfx/components/cometapi/cometapi.py +166 -0
- lfx/components/composio/__init__.py +222 -0
- lfx/components/composio/agentql_composio.py +11 -0
- lfx/components/composio/agiled_composio.py +11 -0
- lfx/components/composio/airtable_composio.py +11 -0
- lfx/components/composio/apollo_composio.py +11 -0
- lfx/components/composio/asana_composio.py +11 -0
- lfx/components/composio/attio_composio.py +11 -0
- lfx/components/composio/bitbucket_composio.py +11 -0
- lfx/components/composio/bolna_composio.py +11 -0
- lfx/components/composio/brightdata_composio.py +11 -0
- lfx/components/composio/calendly_composio.py +11 -0
- lfx/components/composio/canva_composio.py +11 -0
- lfx/components/composio/canvas_composio.py +11 -0
- lfx/components/composio/coda_composio.py +11 -0
- lfx/components/composio/composio_api.py +278 -0
- lfx/components/composio/contentful_composio.py +11 -0
- lfx/components/composio/digicert_composio.py +11 -0
- lfx/components/composio/discord_composio.py +11 -0
- lfx/components/composio/dropbox_compnent.py +11 -0
- lfx/components/composio/elevenlabs_composio.py +11 -0
- lfx/components/composio/exa_composio.py +11 -0
- lfx/components/composio/figma_composio.py +11 -0
- lfx/components/composio/finage_composio.py +11 -0
- lfx/components/composio/firecrawl_composio.py +11 -0
- lfx/components/composio/fireflies_composio.py +11 -0
- lfx/components/composio/fixer_composio.py +11 -0
- lfx/components/composio/flexisign_composio.py +11 -0
- lfx/components/composio/freshdesk_composio.py +11 -0
- lfx/components/composio/github_composio.py +11 -0
- lfx/components/composio/gmail_composio.py +38 -0
- lfx/components/composio/googlebigquery_composio.py +11 -0
- lfx/components/composio/googlecalendar_composio.py +11 -0
- lfx/components/composio/googleclassroom_composio.py +11 -0
- lfx/components/composio/googledocs_composio.py +11 -0
- lfx/components/composio/googlemeet_composio.py +11 -0
- lfx/components/composio/googlesheets_composio.py +11 -0
- lfx/components/composio/googletasks_composio.py +8 -0
- lfx/components/composio/heygen_composio.py +11 -0
- lfx/components/composio/instagram_composio.py +11 -0
- lfx/components/composio/jira_composio.py +11 -0
- lfx/components/composio/jotform_composio.py +11 -0
- lfx/components/composio/klaviyo_composio.py +11 -0
- lfx/components/composio/linear_composio.py +11 -0
- lfx/components/composio/listennotes_composio.py +11 -0
- lfx/components/composio/mem0_composio.py +11 -0
- lfx/components/composio/miro_composio.py +11 -0
- lfx/components/composio/missive_composio.py +11 -0
- lfx/components/composio/notion_composio.py +11 -0
- lfx/components/composio/onedrive_composio.py +11 -0
- lfx/components/composio/outlook_composio.py +11 -0
- lfx/components/composio/pandadoc_composio.py +11 -0
- lfx/components/composio/peopledatalabs_composio.py +11 -0
- lfx/components/composio/perplexityai_composio.py +11 -0
- lfx/components/composio/reddit_composio.py +11 -0
- lfx/components/composio/serpapi_composio.py +11 -0
- lfx/components/composio/slack_composio.py +11 -0
- lfx/components/composio/slackbot_composio.py +11 -0
- lfx/components/composio/snowflake_composio.py +11 -0
- lfx/components/composio/supabase_composio.py +11 -0
- lfx/components/composio/tavily_composio.py +11 -0
- lfx/components/composio/timelinesai_composio.py +11 -0
- lfx/components/composio/todoist_composio.py +11 -0
- lfx/components/composio/wrike_composio.py +11 -0
- lfx/components/composio/youtube_composio.py +11 -0
- lfx/components/confluence/__init__.py +3 -0
- lfx/components/confluence/confluence.py +84 -0
- lfx/components/couchbase/__init__.py +34 -0
- lfx/components/couchbase/couchbase.py +102 -0
- lfx/components/crewai/__init__.py +49 -0
- lfx/components/crewai/crewai.py +108 -0
- lfx/components/crewai/hierarchical_crew.py +47 -0
- lfx/components/crewai/hierarchical_task.py +45 -0
- lfx/components/crewai/sequential_crew.py +53 -0
- lfx/components/crewai/sequential_task.py +74 -0
- lfx/components/crewai/sequential_task_agent.py +144 -0
- lfx/components/cuga/__init__.py +34 -0
- lfx/components/cuga/cuga_agent.py +730 -0
- lfx/components/custom_component/__init__.py +34 -0
- lfx/components/custom_component/custom_component.py +31 -0
- lfx/components/data/__init__.py +114 -0
- lfx/components/data_source/__init__.py +58 -0
- lfx/components/data_source/api_request.py +577 -0
- lfx/components/data_source/csv_to_data.py +101 -0
- lfx/components/data_source/json_to_data.py +106 -0
- lfx/components/data_source/mock_data.py +398 -0
- lfx/components/data_source/news_search.py +166 -0
- lfx/components/data_source/rss.py +71 -0
- lfx/components/data_source/sql_executor.py +101 -0
- lfx/components/data_source/url.py +311 -0
- lfx/components/data_source/web_search.py +326 -0
- lfx/components/datastax/__init__.py +76 -0
- lfx/components/datastax/astradb_assistant_manager.py +307 -0
- lfx/components/datastax/astradb_chatmemory.py +40 -0
- lfx/components/datastax/astradb_cql.py +288 -0
- lfx/components/datastax/astradb_graph.py +217 -0
- lfx/components/datastax/astradb_tool.py +378 -0
- lfx/components/datastax/astradb_vectorize.py +122 -0
- lfx/components/datastax/astradb_vectorstore.py +449 -0
- lfx/components/datastax/create_assistant.py +59 -0
- lfx/components/datastax/create_thread.py +33 -0
- lfx/components/datastax/dotenv.py +36 -0
- lfx/components/datastax/get_assistant.py +38 -0
- lfx/components/datastax/getenvvar.py +31 -0
- lfx/components/datastax/graph_rag.py +141 -0
- lfx/components/datastax/hcd.py +315 -0
- lfx/components/datastax/list_assistants.py +26 -0
- lfx/components/datastax/run.py +90 -0
- lfx/components/deactivated/__init__.py +15 -0
- lfx/components/deactivated/amazon_kendra.py +66 -0
- lfx/components/deactivated/chat_litellm_model.py +158 -0
- lfx/components/deactivated/code_block_extractor.py +26 -0
- lfx/components/deactivated/documents_to_data.py +22 -0
- lfx/components/deactivated/embed.py +16 -0
- lfx/components/deactivated/extract_key_from_data.py +46 -0
- lfx/components/deactivated/json_document_builder.py +57 -0
- lfx/components/deactivated/list_flows.py +20 -0
- lfx/components/deactivated/mcp_sse.py +61 -0
- lfx/components/deactivated/mcp_stdio.py +62 -0
- lfx/components/deactivated/merge_data.py +93 -0
- lfx/components/deactivated/message.py +37 -0
- lfx/components/deactivated/metal.py +54 -0
- lfx/components/deactivated/multi_query.py +59 -0
- lfx/components/deactivated/retriever.py +43 -0
- lfx/components/deactivated/selective_passthrough.py +77 -0
- lfx/components/deactivated/should_run_next.py +40 -0
- lfx/components/deactivated/split_text.py +63 -0
- lfx/components/deactivated/store_message.py +24 -0
- lfx/components/deactivated/sub_flow.py +124 -0
- lfx/components/deactivated/vectara_self_query.py +76 -0
- lfx/components/deactivated/vector_store.py +24 -0
- lfx/components/deepseek/__init__.py +34 -0
- lfx/components/deepseek/deepseek.py +136 -0
- lfx/components/docling/__init__.py +43 -0
- lfx/components/docling/chunk_docling_document.py +186 -0
- lfx/components/docling/docling_inline.py +238 -0
- lfx/components/docling/docling_remote.py +195 -0
- lfx/components/docling/export_docling_document.py +117 -0
- lfx/components/documentloaders/__init__.py +3 -0
- lfx/components/duckduckgo/__init__.py +3 -0
- lfx/components/duckduckgo/duck_duck_go_search_run.py +92 -0
- lfx/components/elastic/__init__.py +37 -0
- lfx/components/elastic/elasticsearch.py +267 -0
- lfx/components/elastic/opensearch.py +789 -0
- lfx/components/elastic/opensearch_multimodal.py +1575 -0
- lfx/components/embeddings/__init__.py +37 -0
- lfx/components/embeddings/similarity.py +77 -0
- lfx/components/embeddings/text_embedder.py +65 -0
- lfx/components/exa/__init__.py +3 -0
- lfx/components/exa/exa_search.py +68 -0
- lfx/components/files_and_knowledge/__init__.py +47 -0
- lfx/components/files_and_knowledge/directory.py +113 -0
- lfx/components/files_and_knowledge/file.py +841 -0
- lfx/components/files_and_knowledge/ingestion.py +694 -0
- lfx/components/files_and_knowledge/retrieval.py +264 -0
- lfx/components/files_and_knowledge/save_file.py +746 -0
- lfx/components/firecrawl/__init__.py +43 -0
- lfx/components/firecrawl/firecrawl_crawl_api.py +88 -0
- lfx/components/firecrawl/firecrawl_extract_api.py +136 -0
- lfx/components/firecrawl/firecrawl_map_api.py +89 -0
- lfx/components/firecrawl/firecrawl_scrape_api.py +73 -0
- lfx/components/flow_controls/__init__.py +58 -0
- lfx/components/flow_controls/conditional_router.py +208 -0
- lfx/components/flow_controls/data_conditional_router.py +126 -0
- lfx/components/flow_controls/flow_tool.py +111 -0
- lfx/components/flow_controls/listen.py +29 -0
- lfx/components/flow_controls/loop.py +163 -0
- lfx/components/flow_controls/notify.py +88 -0
- lfx/components/flow_controls/pass_message.py +36 -0
- lfx/components/flow_controls/run_flow.py +108 -0
- lfx/components/flow_controls/sub_flow.py +115 -0
- lfx/components/git/__init__.py +4 -0
- lfx/components/git/git.py +262 -0
- lfx/components/git/gitextractor.py +196 -0
- lfx/components/glean/__init__.py +3 -0
- lfx/components/glean/glean_search_api.py +173 -0
- lfx/components/google/__init__.py +17 -0
- lfx/components/google/gmail.py +193 -0
- lfx/components/google/google_bq_sql_executor.py +157 -0
- lfx/components/google/google_drive.py +92 -0
- lfx/components/google/google_drive_search.py +152 -0
- lfx/components/google/google_generative_ai.py +144 -0
- lfx/components/google/google_generative_ai_embeddings.py +141 -0
- lfx/components/google/google_oauth_token.py +89 -0
- lfx/components/google/google_search_api_core.py +68 -0
- lfx/components/google/google_serper_api_core.py +74 -0
- lfx/components/groq/__init__.py +34 -0
- lfx/components/groq/groq.py +143 -0
- lfx/components/helpers/__init__.py +154 -0
- lfx/components/homeassistant/__init__.py +7 -0
- lfx/components/homeassistant/home_assistant_control.py +152 -0
- lfx/components/homeassistant/list_home_assistant_states.py +137 -0
- lfx/components/huggingface/__init__.py +37 -0
- lfx/components/huggingface/huggingface.py +199 -0
- lfx/components/huggingface/huggingface_inference_api.py +106 -0
- lfx/components/ibm/__init__.py +34 -0
- lfx/components/ibm/watsonx.py +207 -0
- lfx/components/ibm/watsonx_embeddings.py +135 -0
- lfx/components/icosacomputing/__init__.py +5 -0
- lfx/components/icosacomputing/combinatorial_reasoner.py +84 -0
- lfx/components/input_output/__init__.py +40 -0
- lfx/components/input_output/chat.py +109 -0
- lfx/components/input_output/chat_output.py +184 -0
- lfx/components/input_output/text.py +27 -0
- lfx/components/input_output/text_output.py +29 -0
- lfx/components/input_output/webhook.py +56 -0
- lfx/components/jigsawstack/__init__.py +23 -0
- lfx/components/jigsawstack/ai_scrape.py +126 -0
- lfx/components/jigsawstack/ai_web_search.py +136 -0
- lfx/components/jigsawstack/file_read.py +115 -0
- lfx/components/jigsawstack/file_upload.py +94 -0
- lfx/components/jigsawstack/image_generation.py +205 -0
- lfx/components/jigsawstack/nsfw.py +60 -0
- lfx/components/jigsawstack/object_detection.py +124 -0
- lfx/components/jigsawstack/sentiment.py +112 -0
- lfx/components/jigsawstack/text_to_sql.py +90 -0
- lfx/components/jigsawstack/text_translate.py +77 -0
- lfx/components/jigsawstack/vocr.py +107 -0
- lfx/components/knowledge_bases/__init__.py +89 -0
- lfx/components/langchain_utilities/__init__.py +109 -0
- lfx/components/langchain_utilities/character.py +53 -0
- lfx/components/langchain_utilities/conversation.py +59 -0
- lfx/components/langchain_utilities/csv_agent.py +175 -0
- lfx/components/langchain_utilities/fake_embeddings.py +26 -0
- lfx/components/langchain_utilities/html_link_extractor.py +35 -0
- lfx/components/langchain_utilities/json_agent.py +100 -0
- lfx/components/langchain_utilities/langchain_hub.py +126 -0
- lfx/components/langchain_utilities/language_recursive.py +49 -0
- lfx/components/langchain_utilities/language_semantic.py +138 -0
- lfx/components/langchain_utilities/llm_checker.py +39 -0
- lfx/components/langchain_utilities/llm_math.py +42 -0
- lfx/components/langchain_utilities/natural_language.py +61 -0
- lfx/components/langchain_utilities/openai_tools.py +53 -0
- lfx/components/langchain_utilities/openapi.py +48 -0
- lfx/components/langchain_utilities/recursive_character.py +60 -0
- lfx/components/langchain_utilities/retrieval_qa.py +83 -0
- lfx/components/langchain_utilities/runnable_executor.py +137 -0
- lfx/components/langchain_utilities/self_query.py +80 -0
- lfx/components/langchain_utilities/spider.py +142 -0
- lfx/components/langchain_utilities/sql.py +40 -0
- lfx/components/langchain_utilities/sql_database.py +35 -0
- lfx/components/langchain_utilities/sql_generator.py +78 -0
- lfx/components/langchain_utilities/tool_calling.py +59 -0
- lfx/components/langchain_utilities/vector_store_info.py +49 -0
- lfx/components/langchain_utilities/vector_store_router.py +33 -0
- lfx/components/langchain_utilities/xml_agent.py +71 -0
- lfx/components/langwatch/__init__.py +3 -0
- lfx/components/langwatch/langwatch.py +278 -0
- lfx/components/link_extractors/__init__.py +3 -0
- lfx/components/llm_operations/__init__.py +46 -0
- lfx/components/llm_operations/batch_run.py +205 -0
- lfx/components/llm_operations/lambda_filter.py +218 -0
- lfx/components/llm_operations/llm_conditional_router.py +421 -0
- lfx/components/llm_operations/llm_selector.py +499 -0
- lfx/components/llm_operations/structured_output.py +244 -0
- lfx/components/lmstudio/__init__.py +34 -0
- lfx/components/lmstudio/lmstudioembeddings.py +89 -0
- lfx/components/lmstudio/lmstudiomodel.py +133 -0
- lfx/components/logic/__init__.py +181 -0
- lfx/components/maritalk/__init__.py +32 -0
- lfx/components/maritalk/maritalk.py +52 -0
- lfx/components/mem0/__init__.py +3 -0
- lfx/components/mem0/mem0_chat_memory.py +147 -0
- lfx/components/milvus/__init__.py +34 -0
- lfx/components/milvus/milvus.py +115 -0
- lfx/components/mistral/__init__.py +37 -0
- lfx/components/mistral/mistral.py +114 -0
- lfx/components/mistral/mistral_embeddings.py +58 -0
- lfx/components/models/__init__.py +89 -0
- lfx/components/models_and_agents/__init__.py +49 -0
- lfx/components/models_and_agents/agent.py +644 -0
- lfx/components/models_and_agents/embedding_model.py +423 -0
- lfx/components/models_and_agents/language_model.py +398 -0
- lfx/components/models_and_agents/mcp_component.py +594 -0
- lfx/components/models_and_agents/memory.py +268 -0
- lfx/components/models_and_agents/prompt.py +67 -0
- lfx/components/mongodb/__init__.py +34 -0
- lfx/components/mongodb/mongodb_atlas.py +213 -0
- lfx/components/needle/__init__.py +3 -0
- lfx/components/needle/needle.py +104 -0
- lfx/components/notdiamond/__init__.py +34 -0
- lfx/components/notdiamond/notdiamond.py +228 -0
- lfx/components/novita/__init__.py +32 -0
- lfx/components/novita/novita.py +130 -0
- lfx/components/nvidia/__init__.py +57 -0
- lfx/components/nvidia/nvidia.py +151 -0
- lfx/components/nvidia/nvidia_embedding.py +77 -0
- lfx/components/nvidia/nvidia_ingest.py +317 -0
- lfx/components/nvidia/nvidia_rerank.py +63 -0
- lfx/components/nvidia/system_assist.py +65 -0
- lfx/components/olivya/__init__.py +3 -0
- lfx/components/olivya/olivya.py +116 -0
- lfx/components/ollama/__init__.py +37 -0
- lfx/components/ollama/ollama.py +548 -0
- lfx/components/ollama/ollama_embeddings.py +103 -0
- lfx/components/openai/__init__.py +37 -0
- lfx/components/openai/openai.py +100 -0
- lfx/components/openai/openai_chat_model.py +176 -0
- lfx/components/openrouter/__init__.py +32 -0
- lfx/components/openrouter/openrouter.py +104 -0
- lfx/components/output_parsers/__init__.py +3 -0
- lfx/components/perplexity/__init__.py +34 -0
- lfx/components/perplexity/perplexity.py +75 -0
- lfx/components/pgvector/__init__.py +34 -0
- lfx/components/pgvector/pgvector.py +72 -0
- lfx/components/pinecone/__init__.py +34 -0
- lfx/components/pinecone/pinecone.py +134 -0
- lfx/components/processing/__init__.py +72 -0
- lfx/components/processing/alter_metadata.py +109 -0
- lfx/components/processing/combine_text.py +40 -0
- lfx/components/processing/converter.py +248 -0
- lfx/components/processing/create_data.py +111 -0
- lfx/components/processing/create_list.py +40 -0
- lfx/components/processing/data_operations.py +528 -0
- lfx/components/processing/data_to_dataframe.py +71 -0
- lfx/components/processing/dataframe_operations.py +313 -0
- lfx/components/processing/dataframe_to_toolset.py +259 -0
- lfx/components/processing/dynamic_create_data.py +357 -0
- lfx/components/processing/extract_key.py +54 -0
- lfx/components/processing/filter_data.py +43 -0
- lfx/components/processing/filter_data_values.py +89 -0
- lfx/components/processing/json_cleaner.py +104 -0
- lfx/components/processing/merge_data.py +91 -0
- lfx/components/processing/message_to_data.py +37 -0
- lfx/components/processing/output_parser.py +46 -0
- lfx/components/processing/parse_data.py +71 -0
- lfx/components/processing/parse_dataframe.py +69 -0
- lfx/components/processing/parse_json_data.py +91 -0
- lfx/components/processing/parser.py +148 -0
- lfx/components/processing/regex.py +83 -0
- lfx/components/processing/select_data.py +49 -0
- lfx/components/processing/split_text.py +141 -0
- lfx/components/processing/store_message.py +91 -0
- lfx/components/processing/update_data.py +161 -0
- lfx/components/prototypes/__init__.py +35 -0
- lfx/components/prototypes/python_function.py +73 -0
- lfx/components/qdrant/__init__.py +34 -0
- lfx/components/qdrant/qdrant.py +109 -0
- lfx/components/redis/__init__.py +37 -0
- lfx/components/redis/redis.py +89 -0
- lfx/components/redis/redis_chat.py +43 -0
- lfx/components/sambanova/__init__.py +32 -0
- lfx/components/sambanova/sambanova.py +84 -0
- lfx/components/scrapegraph/__init__.py +40 -0
- lfx/components/scrapegraph/scrapegraph_markdownify_api.py +64 -0
- lfx/components/scrapegraph/scrapegraph_search_api.py +64 -0
- lfx/components/scrapegraph/scrapegraph_smart_scraper_api.py +71 -0
- lfx/components/searchapi/__init__.py +34 -0
- lfx/components/searchapi/search.py +79 -0
- lfx/components/serpapi/__init__.py +3 -0
- lfx/components/serpapi/serp.py +115 -0
- lfx/components/supabase/__init__.py +34 -0
- lfx/components/supabase/supabase.py +76 -0
- lfx/components/tavily/__init__.py +4 -0
- lfx/components/tavily/tavily_extract.py +117 -0
- lfx/components/tavily/tavily_search.py +212 -0
- lfx/components/textsplitters/__init__.py +3 -0
- lfx/components/toolkits/__init__.py +3 -0
- lfx/components/tools/__init__.py +66 -0
- lfx/components/tools/calculator.py +109 -0
- lfx/components/tools/google_search_api.py +45 -0
- lfx/components/tools/google_serper_api.py +115 -0
- lfx/components/tools/python_code_structured_tool.py +328 -0
- lfx/components/tools/python_repl.py +98 -0
- lfx/components/tools/search_api.py +88 -0
- lfx/components/tools/searxng.py +145 -0
- lfx/components/tools/serp_api.py +120 -0
- lfx/components/tools/tavily_search_tool.py +345 -0
- lfx/components/tools/wikidata_api.py +103 -0
- lfx/components/tools/wikipedia_api.py +50 -0
- lfx/components/tools/yahoo_finance.py +130 -0
- lfx/components/twelvelabs/__init__.py +52 -0
- lfx/components/twelvelabs/convert_astra_results.py +84 -0
- lfx/components/twelvelabs/pegasus_index.py +311 -0
- lfx/components/twelvelabs/split_video.py +301 -0
- lfx/components/twelvelabs/text_embeddings.py +57 -0
- lfx/components/twelvelabs/twelvelabs_pegasus.py +408 -0
- lfx/components/twelvelabs/video_embeddings.py +100 -0
- lfx/components/twelvelabs/video_file.py +191 -0
- lfx/components/unstructured/__init__.py +3 -0
- lfx/components/unstructured/unstructured.py +121 -0
- lfx/components/upstash/__init__.py +34 -0
- lfx/components/upstash/upstash.py +124 -0
- lfx/components/utilities/__init__.py +43 -0
- lfx/components/utilities/calculator_core.py +89 -0
- lfx/components/utilities/current_date.py +42 -0
- lfx/components/utilities/id_generator.py +42 -0
- lfx/components/utilities/python_repl_core.py +98 -0
- lfx/components/vectara/__init__.py +37 -0
- lfx/components/vectara/vectara.py +97 -0
- lfx/components/vectara/vectara_rag.py +164 -0
- lfx/components/vectorstores/__init__.py +34 -0
- lfx/components/vectorstores/local_db.py +270 -0
- lfx/components/vertexai/__init__.py +37 -0
- lfx/components/vertexai/vertexai.py +71 -0
- lfx/components/vertexai/vertexai_embeddings.py +67 -0
- lfx/components/vlmrun/__init__.py +34 -0
- lfx/components/vlmrun/vlmrun_transcription.py +224 -0
- lfx/components/weaviate/__init__.py +34 -0
- lfx/components/weaviate/weaviate.py +89 -0
- lfx/components/wikipedia/__init__.py +4 -0
- lfx/components/wikipedia/wikidata.py +86 -0
- lfx/components/wikipedia/wikipedia.py +53 -0
- lfx/components/wolframalpha/__init__.py +3 -0
- lfx/components/wolframalpha/wolfram_alpha_api.py +54 -0
- lfx/components/xai/__init__.py +32 -0
- lfx/components/xai/xai.py +167 -0
- lfx/components/yahoosearch/__init__.py +3 -0
- lfx/components/yahoosearch/yahoo.py +137 -0
- lfx/components/youtube/__init__.py +52 -0
- lfx/components/youtube/channel.py +227 -0
- lfx/components/youtube/comments.py +231 -0
- lfx/components/youtube/playlist.py +33 -0
- lfx/components/youtube/search.py +120 -0
- lfx/components/youtube/trending.py +285 -0
- lfx/components/youtube/video_details.py +263 -0
- lfx/components/youtube/youtube_transcripts.py +206 -0
- lfx/components/zep/__init__.py +3 -0
- lfx/components/zep/zep.py +45 -0
- lfx/constants.py +6 -0
- lfx/custom/__init__.py +7 -0
- lfx/custom/attributes.py +87 -0
- lfx/custom/code_parser/__init__.py +3 -0
- lfx/custom/code_parser/code_parser.py +361 -0
- lfx/custom/custom_component/__init__.py +0 -0
- lfx/custom/custom_component/base_component.py +128 -0
- lfx/custom/custom_component/component.py +1890 -0
- lfx/custom/custom_component/component_with_cache.py +8 -0
- lfx/custom/custom_component/custom_component.py +650 -0
- lfx/custom/dependency_analyzer.py +165 -0
- lfx/custom/directory_reader/__init__.py +3 -0
- lfx/custom/directory_reader/directory_reader.py +359 -0
- lfx/custom/directory_reader/utils.py +171 -0
- lfx/custom/eval.py +12 -0
- lfx/custom/schema.py +32 -0
- lfx/custom/tree_visitor.py +21 -0
- lfx/custom/utils.py +877 -0
- lfx/custom/validate.py +523 -0
- lfx/events/__init__.py +1 -0
- lfx/events/event_manager.py +110 -0
- lfx/exceptions/__init__.py +0 -0
- lfx/exceptions/component.py +15 -0
- lfx/field_typing/__init__.py +91 -0
- lfx/field_typing/constants.py +216 -0
- lfx/field_typing/range_spec.py +35 -0
- lfx/graph/__init__.py +6 -0
- lfx/graph/edge/__init__.py +0 -0
- lfx/graph/edge/base.py +300 -0
- lfx/graph/edge/schema.py +119 -0
- lfx/graph/edge/utils.py +0 -0
- lfx/graph/graph/__init__.py +0 -0
- lfx/graph/graph/ascii.py +202 -0
- lfx/graph/graph/base.py +2298 -0
- lfx/graph/graph/constants.py +63 -0
- lfx/graph/graph/runnable_vertices_manager.py +133 -0
- lfx/graph/graph/schema.py +53 -0
- lfx/graph/graph/state_model.py +66 -0
- lfx/graph/graph/utils.py +1024 -0
- lfx/graph/schema.py +75 -0
- lfx/graph/state/__init__.py +0 -0
- lfx/graph/state/model.py +250 -0
- lfx/graph/utils.py +206 -0
- lfx/graph/vertex/__init__.py +0 -0
- lfx/graph/vertex/base.py +826 -0
- lfx/graph/vertex/constants.py +0 -0
- lfx/graph/vertex/exceptions.py +4 -0
- lfx/graph/vertex/param_handler.py +316 -0
- lfx/graph/vertex/schema.py +26 -0
- lfx/graph/vertex/utils.py +19 -0
- lfx/graph/vertex/vertex_types.py +489 -0
- lfx/helpers/__init__.py +141 -0
- lfx/helpers/base_model.py +71 -0
- lfx/helpers/custom.py +13 -0
- lfx/helpers/data.py +167 -0
- lfx/helpers/flow.py +308 -0
- lfx/inputs/__init__.py +68 -0
- lfx/inputs/constants.py +2 -0
- lfx/inputs/input_mixin.py +352 -0
- lfx/inputs/inputs.py +718 -0
- lfx/inputs/validators.py +19 -0
- lfx/interface/__init__.py +6 -0
- lfx/interface/components.py +897 -0
- lfx/interface/importing/__init__.py +5 -0
- lfx/interface/importing/utils.py +39 -0
- lfx/interface/initialize/__init__.py +3 -0
- lfx/interface/initialize/loading.py +317 -0
- lfx/interface/listing.py +26 -0
- lfx/interface/run.py +16 -0
- lfx/interface/utils.py +111 -0
- lfx/io/__init__.py +63 -0
- lfx/io/schema.py +295 -0
- lfx/load/__init__.py +8 -0
- lfx/load/load.py +256 -0
- lfx/load/utils.py +99 -0
- lfx/log/__init__.py +5 -0
- lfx/log/logger.py +411 -0
- lfx/logging/__init__.py +11 -0
- lfx/logging/logger.py +24 -0
- lfx/memory/__init__.py +70 -0
- lfx/memory/stubs.py +302 -0
- lfx/processing/__init__.py +1 -0
- lfx/processing/process.py +238 -0
- lfx/processing/utils.py +25 -0
- lfx/py.typed +0 -0
- lfx/schema/__init__.py +66 -0
- lfx/schema/artifact.py +83 -0
- lfx/schema/content_block.py +62 -0
- lfx/schema/content_types.py +91 -0
- lfx/schema/cross_module.py +80 -0
- lfx/schema/data.py +309 -0
- lfx/schema/dataframe.py +210 -0
- lfx/schema/dotdict.py +74 -0
- lfx/schema/encoders.py +13 -0
- lfx/schema/graph.py +47 -0
- lfx/schema/image.py +184 -0
- lfx/schema/json_schema.py +186 -0
- lfx/schema/log.py +62 -0
- lfx/schema/message.py +493 -0
- lfx/schema/openai_responses_schemas.py +74 -0
- lfx/schema/properties.py +41 -0
- lfx/schema/schema.py +180 -0
- lfx/schema/serialize.py +13 -0
- lfx/schema/table.py +142 -0
- lfx/schema/validators.py +114 -0
- lfx/serialization/__init__.py +5 -0
- lfx/serialization/constants.py +2 -0
- lfx/serialization/serialization.py +314 -0
- lfx/services/__init__.py +26 -0
- lfx/services/base.py +28 -0
- lfx/services/cache/__init__.py +6 -0
- lfx/services/cache/base.py +183 -0
- lfx/services/cache/service.py +166 -0
- lfx/services/cache/utils.py +169 -0
- lfx/services/chat/__init__.py +1 -0
- lfx/services/chat/config.py +2 -0
- lfx/services/chat/schema.py +10 -0
- lfx/services/database/__init__.py +5 -0
- lfx/services/database/service.py +25 -0
- lfx/services/deps.py +194 -0
- lfx/services/factory.py +19 -0
- lfx/services/initialize.py +19 -0
- lfx/services/interfaces.py +103 -0
- lfx/services/manager.py +185 -0
- lfx/services/mcp_composer/__init__.py +6 -0
- lfx/services/mcp_composer/factory.py +16 -0
- lfx/services/mcp_composer/service.py +1441 -0
- lfx/services/schema.py +21 -0
- lfx/services/session.py +87 -0
- lfx/services/settings/__init__.py +3 -0
- lfx/services/settings/auth.py +133 -0
- lfx/services/settings/base.py +668 -0
- lfx/services/settings/constants.py +43 -0
- lfx/services/settings/factory.py +23 -0
- lfx/services/settings/feature_flags.py +11 -0
- lfx/services/settings/service.py +35 -0
- lfx/services/settings/utils.py +40 -0
- lfx/services/shared_component_cache/__init__.py +1 -0
- lfx/services/shared_component_cache/factory.py +30 -0
- lfx/services/shared_component_cache/service.py +9 -0
- lfx/services/storage/__init__.py +5 -0
- lfx/services/storage/local.py +185 -0
- lfx/services/storage/service.py +177 -0
- lfx/services/tracing/__init__.py +1 -0
- lfx/services/tracing/service.py +21 -0
- lfx/settings.py +6 -0
- lfx/template/__init__.py +6 -0
- lfx/template/field/__init__.py +0 -0
- lfx/template/field/base.py +260 -0
- lfx/template/field/prompt.py +15 -0
- lfx/template/frontend_node/__init__.py +6 -0
- lfx/template/frontend_node/base.py +214 -0
- lfx/template/frontend_node/constants.py +65 -0
- lfx/template/frontend_node/custom_components.py +79 -0
- lfx/template/template/__init__.py +0 -0
- lfx/template/template/base.py +100 -0
- lfx/template/utils.py +217 -0
- lfx/type_extraction/__init__.py +19 -0
- lfx/type_extraction/type_extraction.py +75 -0
- lfx/type_extraction.py +80 -0
- lfx/utils/__init__.py +1 -0
- lfx/utils/async_helpers.py +42 -0
- lfx/utils/component_utils.py +154 -0
- lfx/utils/concurrency.py +60 -0
- lfx/utils/connection_string_parser.py +11 -0
- lfx/utils/constants.py +233 -0
- lfx/utils/data_structure.py +212 -0
- lfx/utils/exceptions.py +22 -0
- lfx/utils/helpers.py +34 -0
- lfx/utils/image.py +79 -0
- lfx/utils/langflow_utils.py +52 -0
- lfx/utils/lazy_load.py +15 -0
- lfx/utils/request_utils.py +18 -0
- lfx/utils/schemas.py +139 -0
- lfx/utils/ssrf_protection.py +384 -0
- lfx/utils/util.py +626 -0
- lfx/utils/util_strings.py +56 -0
- lfx/utils/validate_cloud.py +26 -0
- lfx/utils/version.py +24 -0
- lfx_nightly-0.2.0.dev25.dist-info/METADATA +312 -0
- lfx_nightly-0.2.0.dev25.dist-info/RECORD +769 -0
- lfx_nightly-0.2.0.dev25.dist-info/WHEEL +4 -0
- lfx_nightly-0.2.0.dev25.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import re
|
|
2
|
+
|
|
3
|
+
from lfx.custom.custom_component.component import Component
|
|
4
|
+
from lfx.io import BoolInput, DropdownInput, IntInput, MessageInput, MessageTextInput, Output
|
|
5
|
+
from lfx.schema.message import Message
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ConditionalRouterComponent(Component):
|
|
9
|
+
display_name = "If-Else"
|
|
10
|
+
description = "Routes an input message to a corresponding output based on text comparison."
|
|
11
|
+
documentation: str = "https://docs.langflow.org/if-else"
|
|
12
|
+
icon = "split"
|
|
13
|
+
name = "ConditionalRouter"
|
|
14
|
+
|
|
15
|
+
def __init__(self, *args, **kwargs):
|
|
16
|
+
super().__init__(*args, **kwargs)
|
|
17
|
+
self.__iteration_updated = False
|
|
18
|
+
|
|
19
|
+
inputs = [
|
|
20
|
+
MessageTextInput(
|
|
21
|
+
name="input_text",
|
|
22
|
+
display_name="Text Input",
|
|
23
|
+
info="The primary text input for the operation.",
|
|
24
|
+
required=True,
|
|
25
|
+
),
|
|
26
|
+
DropdownInput(
|
|
27
|
+
name="operator",
|
|
28
|
+
display_name="Operator",
|
|
29
|
+
options=[
|
|
30
|
+
"equals",
|
|
31
|
+
"not equals",
|
|
32
|
+
"contains",
|
|
33
|
+
"starts with",
|
|
34
|
+
"ends with",
|
|
35
|
+
"regex",
|
|
36
|
+
"less than",
|
|
37
|
+
"less than or equal",
|
|
38
|
+
"greater than",
|
|
39
|
+
"greater than or equal",
|
|
40
|
+
],
|
|
41
|
+
info="The operator to apply for comparing the texts.",
|
|
42
|
+
value="equals",
|
|
43
|
+
real_time_refresh=True,
|
|
44
|
+
),
|
|
45
|
+
MessageTextInput(
|
|
46
|
+
name="match_text",
|
|
47
|
+
display_name="Match Text",
|
|
48
|
+
info="The text input to compare against.",
|
|
49
|
+
required=True,
|
|
50
|
+
),
|
|
51
|
+
BoolInput(
|
|
52
|
+
name="case_sensitive",
|
|
53
|
+
display_name="Case Sensitive",
|
|
54
|
+
info="If true, the comparison will be case sensitive.",
|
|
55
|
+
value=True,
|
|
56
|
+
advanced=True,
|
|
57
|
+
),
|
|
58
|
+
MessageInput(
|
|
59
|
+
name="true_case_message",
|
|
60
|
+
display_name="Case True",
|
|
61
|
+
info="The message to pass if the condition is True.",
|
|
62
|
+
advanced=True,
|
|
63
|
+
),
|
|
64
|
+
MessageInput(
|
|
65
|
+
name="false_case_message",
|
|
66
|
+
display_name="Case False",
|
|
67
|
+
info="The message to pass if the condition is False.",
|
|
68
|
+
advanced=True,
|
|
69
|
+
),
|
|
70
|
+
IntInput(
|
|
71
|
+
name="max_iterations",
|
|
72
|
+
display_name="Max Iterations",
|
|
73
|
+
info="The maximum number of iterations for the conditional router.",
|
|
74
|
+
value=10,
|
|
75
|
+
advanced=True,
|
|
76
|
+
),
|
|
77
|
+
DropdownInput(
|
|
78
|
+
name="default_route",
|
|
79
|
+
display_name="Default Route",
|
|
80
|
+
options=["true_result", "false_result"],
|
|
81
|
+
info="The default route to take when max iterations are reached.",
|
|
82
|
+
value="false_result",
|
|
83
|
+
advanced=True,
|
|
84
|
+
),
|
|
85
|
+
]
|
|
86
|
+
|
|
87
|
+
outputs = [
|
|
88
|
+
Output(display_name="True", name="true_result", method="true_response", group_outputs=True),
|
|
89
|
+
Output(display_name="False", name="false_result", method="false_response", group_outputs=True),
|
|
90
|
+
]
|
|
91
|
+
|
|
92
|
+
def _pre_run_setup(self):
|
|
93
|
+
self.__iteration_updated = False
|
|
94
|
+
|
|
95
|
+
def evaluate_condition(self, input_text: str, match_text: str, operator: str, *, case_sensitive: bool) -> bool:
|
|
96
|
+
if not case_sensitive and operator != "regex":
|
|
97
|
+
input_text = input_text.lower()
|
|
98
|
+
match_text = match_text.lower()
|
|
99
|
+
|
|
100
|
+
if operator == "equals":
|
|
101
|
+
return input_text == match_text
|
|
102
|
+
if operator == "not equals":
|
|
103
|
+
return input_text != match_text
|
|
104
|
+
if operator == "contains":
|
|
105
|
+
return match_text in input_text
|
|
106
|
+
if operator == "starts with":
|
|
107
|
+
return input_text.startswith(match_text)
|
|
108
|
+
if operator == "ends with":
|
|
109
|
+
return input_text.endswith(match_text)
|
|
110
|
+
if operator == "regex":
|
|
111
|
+
try:
|
|
112
|
+
return bool(re.match(match_text, input_text))
|
|
113
|
+
except re.error:
|
|
114
|
+
return False # Return False if the regex is invalid
|
|
115
|
+
if operator in ["less than", "less than or equal", "greater than", "greater than or equal"]:
|
|
116
|
+
try:
|
|
117
|
+
input_num = float(input_text)
|
|
118
|
+
match_num = float(match_text)
|
|
119
|
+
if operator == "less than":
|
|
120
|
+
return input_num < match_num
|
|
121
|
+
if operator == "less than or equal":
|
|
122
|
+
return input_num <= match_num
|
|
123
|
+
if operator == "greater than":
|
|
124
|
+
return input_num > match_num
|
|
125
|
+
if operator == "greater than or equal":
|
|
126
|
+
return input_num >= match_num
|
|
127
|
+
except ValueError:
|
|
128
|
+
return False # Invalid number format for comparison
|
|
129
|
+
return False
|
|
130
|
+
|
|
131
|
+
def iterate_and_stop_once(self, route_to_stop: str):
|
|
132
|
+
"""Handles cycle iteration counting and branch exclusion.
|
|
133
|
+
|
|
134
|
+
Uses two complementary mechanisms:
|
|
135
|
+
1. stop() - ACTIVE/INACTIVE state for cycle management (gets reset each iteration)
|
|
136
|
+
2. exclude_branch_conditionally() - Persistent exclusion for conditional routing
|
|
137
|
+
|
|
138
|
+
When max_iterations is reached, breaks the cycle by allowing the default_route to execute.
|
|
139
|
+
"""
|
|
140
|
+
if not self.__iteration_updated:
|
|
141
|
+
self.update_ctx({f"{self._id}_iteration": self.ctx.get(f"{self._id}_iteration", 0) + 1})
|
|
142
|
+
self.__iteration_updated = True
|
|
143
|
+
current_iteration = self.ctx.get(f"{self._id}_iteration", 0)
|
|
144
|
+
|
|
145
|
+
# Check if max iterations reached and we're trying to stop the default route
|
|
146
|
+
if current_iteration >= self.max_iterations and route_to_stop == self.default_route:
|
|
147
|
+
# Clear ALL conditional exclusions to allow default route to execute
|
|
148
|
+
if self._id in self.graph.conditional_exclusion_sources:
|
|
149
|
+
previous_exclusions = self.graph.conditional_exclusion_sources[self._id]
|
|
150
|
+
self.graph.conditionally_excluded_vertices -= previous_exclusions
|
|
151
|
+
del self.graph.conditional_exclusion_sources[self._id]
|
|
152
|
+
|
|
153
|
+
# Switch which route to stop - stop the NON-default route to break the cycle
|
|
154
|
+
route_to_stop = "true_result" if route_to_stop == "false_result" else "false_result"
|
|
155
|
+
|
|
156
|
+
# Call stop to break the cycle
|
|
157
|
+
self.stop(route_to_stop)
|
|
158
|
+
# Don't apply conditional exclusion when breaking cycle
|
|
159
|
+
return
|
|
160
|
+
|
|
161
|
+
# Normal case: Use BOTH mechanisms
|
|
162
|
+
# 1. stop() for cycle management (marks INACTIVE, updates run manager, gets reset)
|
|
163
|
+
self.stop(route_to_stop)
|
|
164
|
+
|
|
165
|
+
# 2. Conditional exclusion for persistent routing (doesn't get reset except by this router)
|
|
166
|
+
self.graph.exclude_branch_conditionally(self._id, output_name=route_to_stop)
|
|
167
|
+
|
|
168
|
+
def true_response(self) -> Message:
|
|
169
|
+
result = self.evaluate_condition(
|
|
170
|
+
self.input_text, self.match_text, self.operator, case_sensitive=self.case_sensitive
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
# Check if we should force output due to max_iterations on default route
|
|
174
|
+
current_iteration = self.ctx.get(f"{self._id}_iteration", 0)
|
|
175
|
+
force_output = current_iteration >= self.max_iterations and self.default_route == "true_result"
|
|
176
|
+
|
|
177
|
+
if result or force_output:
|
|
178
|
+
self.status = self.true_case_message
|
|
179
|
+
if not force_output: # Only stop the other branch if not forcing due to max iterations
|
|
180
|
+
self.iterate_and_stop_once("false_result")
|
|
181
|
+
return self.true_case_message
|
|
182
|
+
self.iterate_and_stop_once("true_result")
|
|
183
|
+
return Message(content="")
|
|
184
|
+
|
|
185
|
+
def false_response(self) -> Message:
|
|
186
|
+
result = self.evaluate_condition(
|
|
187
|
+
self.input_text, self.match_text, self.operator, case_sensitive=self.case_sensitive
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
if not result:
|
|
191
|
+
self.status = self.false_case_message
|
|
192
|
+
self.iterate_and_stop_once("true_result")
|
|
193
|
+
return self.false_case_message
|
|
194
|
+
|
|
195
|
+
self.iterate_and_stop_once("false_result")
|
|
196
|
+
return Message(content="")
|
|
197
|
+
|
|
198
|
+
def update_build_config(self, build_config: dict, field_value: str, field_name: str | None = None) -> dict:
|
|
199
|
+
if field_name == "operator":
|
|
200
|
+
if field_value == "regex":
|
|
201
|
+
build_config.pop("case_sensitive", None)
|
|
202
|
+
elif "case_sensitive" not in build_config:
|
|
203
|
+
case_sensitive_input = next(
|
|
204
|
+
(input_field for input_field in self.inputs if input_field.name == "case_sensitive"), None
|
|
205
|
+
)
|
|
206
|
+
if case_sensitive_input:
|
|
207
|
+
build_config["case_sensitive"] = case_sensitive_input.to_dict()
|
|
208
|
+
return build_config
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from lfx.custom.custom_component.component import Component
|
|
4
|
+
from lfx.io import DataInput, DropdownInput, MessageTextInput, Output
|
|
5
|
+
from lfx.schema.data import Data
|
|
6
|
+
from lfx.schema.dotdict import dotdict
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class DataConditionalRouterComponent(Component):
|
|
10
|
+
display_name = "Condition"
|
|
11
|
+
description = "Route Data object(s) based on a condition applied to a specified key, including boolean validation."
|
|
12
|
+
icon = "split"
|
|
13
|
+
name = "DataConditionalRouter"
|
|
14
|
+
legacy = True
|
|
15
|
+
replacement = ["logic.ConditionalRouter"]
|
|
16
|
+
|
|
17
|
+
inputs = [
|
|
18
|
+
DataInput(
|
|
19
|
+
name="data_input",
|
|
20
|
+
display_name="Data Input",
|
|
21
|
+
info="The Data object or list of Data objects to process",
|
|
22
|
+
is_list=True,
|
|
23
|
+
),
|
|
24
|
+
MessageTextInput(
|
|
25
|
+
name="key_name",
|
|
26
|
+
display_name="Key Name",
|
|
27
|
+
info="The name of the key in the Data object(s) to check",
|
|
28
|
+
),
|
|
29
|
+
DropdownInput(
|
|
30
|
+
name="operator",
|
|
31
|
+
display_name="Operator",
|
|
32
|
+
options=["equals", "not equals", "contains", "starts with", "ends with", "boolean validator"],
|
|
33
|
+
info="The operator to apply for comparing the values. 'boolean validator' treats the value as a boolean.",
|
|
34
|
+
value="equals",
|
|
35
|
+
),
|
|
36
|
+
MessageTextInput(
|
|
37
|
+
name="compare_value",
|
|
38
|
+
display_name="Match Text",
|
|
39
|
+
info="The value to compare against (not used for boolean validator)",
|
|
40
|
+
),
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
outputs = [
|
|
44
|
+
Output(display_name="True Output", name="true_output", method="process_data"),
|
|
45
|
+
Output(display_name="False Output", name="false_output", method="process_data"),
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
def compare_values(self, item_value: str, compare_value: str, operator: str) -> bool:
|
|
49
|
+
if operator == "equals":
|
|
50
|
+
return item_value == compare_value
|
|
51
|
+
if operator == "not equals":
|
|
52
|
+
return item_value != compare_value
|
|
53
|
+
if operator == "contains":
|
|
54
|
+
return compare_value in item_value
|
|
55
|
+
if operator == "starts with":
|
|
56
|
+
return item_value.startswith(compare_value)
|
|
57
|
+
if operator == "ends with":
|
|
58
|
+
return item_value.endswith(compare_value)
|
|
59
|
+
if operator == "boolean validator":
|
|
60
|
+
return self.parse_boolean(item_value)
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
def parse_boolean(self, value):
|
|
64
|
+
if isinstance(value, bool):
|
|
65
|
+
return value
|
|
66
|
+
if isinstance(value, str):
|
|
67
|
+
return value.lower() in {"true", "1", "yes", "y", "on"}
|
|
68
|
+
return bool(value)
|
|
69
|
+
|
|
70
|
+
def validate_input(self, data_item: Data) -> bool:
|
|
71
|
+
if not isinstance(data_item, Data):
|
|
72
|
+
self.status = "Input is not a Data object"
|
|
73
|
+
return False
|
|
74
|
+
if self.key_name not in data_item.data:
|
|
75
|
+
self.status = f"Key '{self.key_name}' not found in Data"
|
|
76
|
+
return False
|
|
77
|
+
return True
|
|
78
|
+
|
|
79
|
+
def process_data(self) -> Data | list[Data]:
|
|
80
|
+
if isinstance(self.data_input, list):
|
|
81
|
+
true_output = []
|
|
82
|
+
false_output = []
|
|
83
|
+
for item in self.data_input:
|
|
84
|
+
if self.validate_input(item):
|
|
85
|
+
result = self.process_single_data(item)
|
|
86
|
+
if result:
|
|
87
|
+
true_output.append(item)
|
|
88
|
+
else:
|
|
89
|
+
false_output.append(item)
|
|
90
|
+
self.stop("false_output" if true_output else "true_output")
|
|
91
|
+
return true_output or false_output
|
|
92
|
+
if not self.validate_input(self.data_input):
|
|
93
|
+
return Data(data={"error": self.status})
|
|
94
|
+
result = self.process_single_data(self.data_input)
|
|
95
|
+
self.stop("false_output" if result else "true_output")
|
|
96
|
+
return self.data_input
|
|
97
|
+
|
|
98
|
+
def process_single_data(self, data_item: Data) -> bool:
|
|
99
|
+
item_value = data_item.data[self.key_name]
|
|
100
|
+
operator = self.operator
|
|
101
|
+
|
|
102
|
+
if operator == "boolean validator":
|
|
103
|
+
condition_met = self.parse_boolean(item_value)
|
|
104
|
+
condition_description = f"Boolean validation of '{self.key_name}'"
|
|
105
|
+
else:
|
|
106
|
+
compare_value = self.compare_value
|
|
107
|
+
condition_met = self.compare_values(str(item_value), compare_value, operator)
|
|
108
|
+
condition_description = f"{self.key_name} {operator} {compare_value}"
|
|
109
|
+
|
|
110
|
+
if condition_met:
|
|
111
|
+
self.status = f"Condition met: {condition_description}"
|
|
112
|
+
return True
|
|
113
|
+
self.status = f"Condition not met: {condition_description}"
|
|
114
|
+
return False
|
|
115
|
+
|
|
116
|
+
def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
|
117
|
+
if field_name == "operator":
|
|
118
|
+
if field_value == "boolean validator":
|
|
119
|
+
build_config["compare_value"]["show"] = False
|
|
120
|
+
build_config["compare_value"]["advanced"] = True
|
|
121
|
+
build_config["compare_value"]["value"] = None
|
|
122
|
+
else:
|
|
123
|
+
build_config["compare_value"]["show"] = True
|
|
124
|
+
build_config["compare_value"]["advanced"] = False
|
|
125
|
+
|
|
126
|
+
return build_config
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from typing import Any
|
|
2
|
+
|
|
3
|
+
from typing_extensions import override
|
|
4
|
+
|
|
5
|
+
from lfx.base.langchain_utilities.model import LCToolComponent
|
|
6
|
+
from lfx.base.tools.flow_tool import FlowTool
|
|
7
|
+
from lfx.field_typing import Tool
|
|
8
|
+
from lfx.graph.graph.base import Graph
|
|
9
|
+
from lfx.helpers import get_flow_inputs
|
|
10
|
+
from lfx.io import BoolInput, DropdownInput, Output, StrInput
|
|
11
|
+
from lfx.log.logger import logger
|
|
12
|
+
from lfx.schema.data import Data
|
|
13
|
+
from lfx.schema.dotdict import dotdict
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class FlowToolComponent(LCToolComponent):
|
|
17
|
+
display_name = "Flow as Tool"
|
|
18
|
+
description = "Construct a Tool from a function that runs the loaded Flow."
|
|
19
|
+
field_order = ["flow_name", "name", "description", "return_direct"]
|
|
20
|
+
trace_type = "tool"
|
|
21
|
+
name = "FlowTool"
|
|
22
|
+
legacy: bool = True
|
|
23
|
+
replacement = ["logic.RunFlow"]
|
|
24
|
+
icon = "hammer"
|
|
25
|
+
|
|
26
|
+
async def get_flow_names(self) -> list[str]:
|
|
27
|
+
flow_datas = await self.alist_flows()
|
|
28
|
+
return [flow_data.data["name"] for flow_data in flow_datas]
|
|
29
|
+
|
|
30
|
+
async def get_flow(self, flow_name: str) -> Data | None:
|
|
31
|
+
"""Retrieves a flow by its name.
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
flow_name (str): The name of the flow to retrieve.
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
Optional[Text]: The flow record if found, None otherwise.
|
|
38
|
+
"""
|
|
39
|
+
flow_datas = await self.alist_flows()
|
|
40
|
+
for flow_data in flow_datas:
|
|
41
|
+
if flow_data.data["name"] == flow_name:
|
|
42
|
+
return flow_data
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
@override
|
|
46
|
+
async def update_build_config(self, build_config: dotdict, field_value: Any, field_name: str | None = None):
|
|
47
|
+
if field_name == "flow_name":
|
|
48
|
+
build_config["flow_name"]["options"] = self.get_flow_names()
|
|
49
|
+
|
|
50
|
+
return build_config
|
|
51
|
+
|
|
52
|
+
inputs = [
|
|
53
|
+
DropdownInput(
|
|
54
|
+
name="flow_name", display_name="Flow Name", info="The name of the flow to run.", refresh_button=True
|
|
55
|
+
),
|
|
56
|
+
StrInput(
|
|
57
|
+
name="tool_name",
|
|
58
|
+
display_name="Name",
|
|
59
|
+
info="The name of the tool.",
|
|
60
|
+
),
|
|
61
|
+
StrInput(
|
|
62
|
+
name="tool_description",
|
|
63
|
+
display_name="Description",
|
|
64
|
+
info="The description of the tool; defaults to the Flow's description.",
|
|
65
|
+
),
|
|
66
|
+
BoolInput(
|
|
67
|
+
name="return_direct",
|
|
68
|
+
display_name="Return Direct",
|
|
69
|
+
info="Return the result directly from the Tool.",
|
|
70
|
+
advanced=True,
|
|
71
|
+
),
|
|
72
|
+
]
|
|
73
|
+
|
|
74
|
+
outputs = [
|
|
75
|
+
Output(name="api_build_tool", display_name="Tool", method="build_tool"),
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
async def build_tool(self) -> Tool:
|
|
79
|
+
FlowTool.model_rebuild()
|
|
80
|
+
if "flow_name" not in self._attributes or not self._attributes["flow_name"]:
|
|
81
|
+
msg = "Flow name is required"
|
|
82
|
+
raise ValueError(msg)
|
|
83
|
+
flow_name = self._attributes["flow_name"]
|
|
84
|
+
flow_data = await self.get_flow(flow_name)
|
|
85
|
+
if not flow_data:
|
|
86
|
+
msg = "Flow not found."
|
|
87
|
+
raise ValueError(msg)
|
|
88
|
+
graph = Graph.from_payload(
|
|
89
|
+
flow_data.data["data"],
|
|
90
|
+
user_id=str(self.user_id),
|
|
91
|
+
)
|
|
92
|
+
try:
|
|
93
|
+
graph.set_run_id(self.graph.run_id)
|
|
94
|
+
except Exception: # noqa: BLE001
|
|
95
|
+
logger.warning("Failed to set run_id", exc_info=True)
|
|
96
|
+
inputs = get_flow_inputs(graph)
|
|
97
|
+
tool_description = self.tool_description.strip() or flow_data.description
|
|
98
|
+
tool = FlowTool(
|
|
99
|
+
name=self.tool_name,
|
|
100
|
+
description=tool_description,
|
|
101
|
+
graph=graph,
|
|
102
|
+
return_direct=self.return_direct,
|
|
103
|
+
inputs=inputs,
|
|
104
|
+
flow_id=str(flow_data.id),
|
|
105
|
+
user_id=str(self.user_id),
|
|
106
|
+
session_id=self.graph.session_id if hasattr(self, "graph") else None,
|
|
107
|
+
)
|
|
108
|
+
description_repr = repr(tool.description).strip("'")
|
|
109
|
+
args_str = "\n".join([f"- {arg_name}: {arg_data['description']}" for arg_name, arg_data in tool.args.items()])
|
|
110
|
+
self.status = f"{description_repr}\nArguments:\n{args_str}"
|
|
111
|
+
return tool
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
from lfx.custom import Component
|
|
2
|
+
from lfx.io import Output, StrInput
|
|
3
|
+
from lfx.schema.data import Data
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ListenComponent(Component):
|
|
7
|
+
display_name = "Listen"
|
|
8
|
+
description = "A component to listen for a notification."
|
|
9
|
+
name = "Listen"
|
|
10
|
+
beta: bool = True
|
|
11
|
+
icon = "Radio"
|
|
12
|
+
inputs = [
|
|
13
|
+
StrInput(
|
|
14
|
+
name="context_key",
|
|
15
|
+
display_name="Context Key",
|
|
16
|
+
info="The key of the context to listen for.",
|
|
17
|
+
input_types=["Message"],
|
|
18
|
+
required=True,
|
|
19
|
+
)
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
outputs = [Output(name="data", display_name="Data", method="listen_for_data", cache=False)]
|
|
23
|
+
|
|
24
|
+
def listen_for_data(self) -> Data:
|
|
25
|
+
"""Retrieves a Data object from the component context using the provided context key.
|
|
26
|
+
|
|
27
|
+
If the specified context key does not exist in the context, returns an empty Data object.
|
|
28
|
+
"""
|
|
29
|
+
return self.ctx.get(self.context_key, Data(text=""))
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
from lfx.components.processing.converter import convert_to_data
|
|
2
|
+
from lfx.custom.custom_component.component import Component
|
|
3
|
+
from lfx.inputs.inputs import HandleInput
|
|
4
|
+
from lfx.schema.data import Data
|
|
5
|
+
from lfx.schema.dataframe import DataFrame
|
|
6
|
+
from lfx.schema.message import Message
|
|
7
|
+
from lfx.template.field.base import Output
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class LoopComponent(Component):
|
|
11
|
+
display_name = "Loop"
|
|
12
|
+
description = (
|
|
13
|
+
"Iterates over a list of Data or Message objects, outputting one item at a time and "
|
|
14
|
+
"aggregating results from loop inputs. Message objects are automatically converted to "
|
|
15
|
+
"Data objects for consistent processing."
|
|
16
|
+
)
|
|
17
|
+
documentation: str = "https://docs.langflow.org/loop"
|
|
18
|
+
icon = "infinity"
|
|
19
|
+
|
|
20
|
+
inputs = [
|
|
21
|
+
HandleInput(
|
|
22
|
+
name="data",
|
|
23
|
+
display_name="Inputs",
|
|
24
|
+
info="The initial DataFrame to iterate over.",
|
|
25
|
+
input_types=["DataFrame"],
|
|
26
|
+
),
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
outputs = [
|
|
30
|
+
Output(
|
|
31
|
+
display_name="Item",
|
|
32
|
+
name="item",
|
|
33
|
+
method="item_output",
|
|
34
|
+
allows_loop=True,
|
|
35
|
+
loop_types=["Message"],
|
|
36
|
+
group_outputs=True,
|
|
37
|
+
),
|
|
38
|
+
Output(display_name="Done", name="done", method="done_output", group_outputs=True),
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
def initialize_data(self) -> None:
|
|
42
|
+
"""Initialize the data list, context index, and aggregated list."""
|
|
43
|
+
if self.ctx.get(f"{self._id}_initialized", False):
|
|
44
|
+
return
|
|
45
|
+
|
|
46
|
+
# Ensure data is a list of Data objects
|
|
47
|
+
data_list = self._validate_data(self.data)
|
|
48
|
+
|
|
49
|
+
# Store the initial data and context variables
|
|
50
|
+
self.update_ctx(
|
|
51
|
+
{
|
|
52
|
+
f"{self._id}_data": data_list,
|
|
53
|
+
f"{self._id}_index": 0,
|
|
54
|
+
f"{self._id}_aggregated": [],
|
|
55
|
+
f"{self._id}_initialized": True,
|
|
56
|
+
}
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
def _convert_message_to_data(self, message: Message) -> Data:
|
|
60
|
+
"""Convert a Message object to a Data object using Type Convert logic."""
|
|
61
|
+
return convert_to_data(message, auto_parse=False)
|
|
62
|
+
|
|
63
|
+
def _validate_data(self, data):
|
|
64
|
+
"""Validate and return a list of Data objects. Message objects are auto-converted to Data."""
|
|
65
|
+
if isinstance(data, DataFrame):
|
|
66
|
+
return data.to_data_list()
|
|
67
|
+
if isinstance(data, Data):
|
|
68
|
+
return [data]
|
|
69
|
+
if isinstance(data, Message):
|
|
70
|
+
# Auto-convert Message to Data
|
|
71
|
+
converted_data = self._convert_message_to_data(data)
|
|
72
|
+
return [converted_data]
|
|
73
|
+
if isinstance(data, list) and all(isinstance(item, (Data, Message)) for item in data):
|
|
74
|
+
# Convert any Message objects in the list to Data objects
|
|
75
|
+
converted_list = []
|
|
76
|
+
for item in data:
|
|
77
|
+
if isinstance(item, Message):
|
|
78
|
+
converted_list.append(self._convert_message_to_data(item))
|
|
79
|
+
else:
|
|
80
|
+
converted_list.append(item)
|
|
81
|
+
return converted_list
|
|
82
|
+
msg = "The 'data' input must be a DataFrame, a list of Data/Message objects, or a single Data/Message object."
|
|
83
|
+
raise TypeError(msg)
|
|
84
|
+
|
|
85
|
+
def evaluate_stop_loop(self) -> bool:
|
|
86
|
+
"""Evaluate whether to stop item or done output."""
|
|
87
|
+
current_index = self.ctx.get(f"{self._id}_index", 0)
|
|
88
|
+
data_length = len(self.ctx.get(f"{self._id}_data", []))
|
|
89
|
+
return current_index > data_length
|
|
90
|
+
|
|
91
|
+
def item_output(self) -> Data:
|
|
92
|
+
"""Output the next item in the list or stop if done."""
|
|
93
|
+
self.initialize_data()
|
|
94
|
+
current_item = Data(text="")
|
|
95
|
+
|
|
96
|
+
if self.evaluate_stop_loop():
|
|
97
|
+
self.stop("item")
|
|
98
|
+
else:
|
|
99
|
+
# Get data list and current index
|
|
100
|
+
data_list, current_index = self.loop_variables()
|
|
101
|
+
if current_index < len(data_list):
|
|
102
|
+
# Output current item and increment index
|
|
103
|
+
try:
|
|
104
|
+
current_item = data_list[current_index]
|
|
105
|
+
except IndexError:
|
|
106
|
+
current_item = Data(text="")
|
|
107
|
+
self.aggregated_output()
|
|
108
|
+
self.update_ctx({f"{self._id}_index": current_index + 1})
|
|
109
|
+
|
|
110
|
+
# Now we need to update the dependencies for the next run
|
|
111
|
+
self.update_dependency()
|
|
112
|
+
return current_item
|
|
113
|
+
|
|
114
|
+
def update_dependency(self):
|
|
115
|
+
item_dependency_id = self.get_incoming_edge_by_target_param("item")
|
|
116
|
+
if item_dependency_id not in self.graph.run_manager.run_predecessors[self._id]:
|
|
117
|
+
self.graph.run_manager.run_predecessors[self._id].append(item_dependency_id)
|
|
118
|
+
# CRITICAL: Also update run_map so remove_from_predecessors() works correctly
|
|
119
|
+
# run_map[predecessor] = list of vertices that depend on predecessor
|
|
120
|
+
if self._id not in self.graph.run_manager.run_map[item_dependency_id]:
|
|
121
|
+
self.graph.run_manager.run_map[item_dependency_id].append(self._id)
|
|
122
|
+
|
|
123
|
+
def done_output(self) -> DataFrame:
|
|
124
|
+
"""Trigger the done output when iteration is complete."""
|
|
125
|
+
self.initialize_data()
|
|
126
|
+
|
|
127
|
+
if self.evaluate_stop_loop():
|
|
128
|
+
self.stop("item")
|
|
129
|
+
self.start("done")
|
|
130
|
+
|
|
131
|
+
aggregated = self.ctx.get(f"{self._id}_aggregated", [])
|
|
132
|
+
|
|
133
|
+
return DataFrame(aggregated)
|
|
134
|
+
self.stop("done")
|
|
135
|
+
return DataFrame([])
|
|
136
|
+
|
|
137
|
+
def loop_variables(self):
|
|
138
|
+
"""Retrieve loop variables from context."""
|
|
139
|
+
return (
|
|
140
|
+
self.ctx.get(f"{self._id}_data", []),
|
|
141
|
+
self.ctx.get(f"{self._id}_index", 0),
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
def aggregated_output(self) -> list[Data]:
|
|
145
|
+
"""Return the aggregated list once all items are processed.
|
|
146
|
+
|
|
147
|
+
Returns Data or Message objects depending on loop input types.
|
|
148
|
+
"""
|
|
149
|
+
self.initialize_data()
|
|
150
|
+
|
|
151
|
+
# Get data list and aggregated list
|
|
152
|
+
data_list = self.ctx.get(f"{self._id}_data", [])
|
|
153
|
+
aggregated = self.ctx.get(f"{self._id}_aggregated", [])
|
|
154
|
+
loop_input = self.item
|
|
155
|
+
|
|
156
|
+
# Append the current loop input to aggregated if it's not already included
|
|
157
|
+
if loop_input is not None and not isinstance(loop_input, str) and len(aggregated) <= len(data_list):
|
|
158
|
+
# If the loop input is a Message, convert it to Data for consistency
|
|
159
|
+
if isinstance(loop_input, Message):
|
|
160
|
+
loop_input = self._convert_message_to_data(loop_input)
|
|
161
|
+
aggregated.append(loop_input)
|
|
162
|
+
self.update_ctx({f"{self._id}_aggregated": aggregated})
|
|
163
|
+
return aggregated
|