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
lfx/utils/util.py
ADDED
|
@@ -0,0 +1,626 @@
|
|
|
1
|
+
import difflib
|
|
2
|
+
import importlib
|
|
3
|
+
import inspect
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
import re
|
|
7
|
+
import socket
|
|
8
|
+
import struct
|
|
9
|
+
from functools import wraps
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
from docstring_parser import parse
|
|
14
|
+
|
|
15
|
+
from lfx.log.logger import logger
|
|
16
|
+
from lfx.schema.data import Data
|
|
17
|
+
from lfx.services.deps import get_settings_service
|
|
18
|
+
from lfx.template.frontend_node.constants import FORCE_SHOW_FIELDS
|
|
19
|
+
from lfx.utils import constants
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def detect_container_environment() -> str | None:
|
|
23
|
+
"""Detect if running in a container and return the appropriate container type.
|
|
24
|
+
|
|
25
|
+
Returns:
|
|
26
|
+
'docker' if running in Docker, 'podman' if running in Podman, None otherwise.
|
|
27
|
+
"""
|
|
28
|
+
# Check for .dockerenv file (Docker)
|
|
29
|
+
if Path("/.dockerenv").exists():
|
|
30
|
+
return "docker"
|
|
31
|
+
|
|
32
|
+
# Check cgroup for container indicators
|
|
33
|
+
try:
|
|
34
|
+
with Path("/proc/self/cgroup").open() as f:
|
|
35
|
+
content = f.read()
|
|
36
|
+
if "docker" in content:
|
|
37
|
+
return "docker"
|
|
38
|
+
if "podman" in content:
|
|
39
|
+
return "podman"
|
|
40
|
+
except (FileNotFoundError, PermissionError):
|
|
41
|
+
pass
|
|
42
|
+
|
|
43
|
+
# Check environment variables (lowercase 'container' is the standard for Podman)
|
|
44
|
+
if os.getenv("container") == "podman": # noqa: SIM112
|
|
45
|
+
return "podman"
|
|
46
|
+
|
|
47
|
+
return None
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_container_host() -> str | None:
|
|
51
|
+
"""Get the hostname to access host services from within a container.
|
|
52
|
+
|
|
53
|
+
Tries multiple methods to find the correct hostname:
|
|
54
|
+
1. host.containers.internal (Podman) or host.docker.internal (Docker)
|
|
55
|
+
2. Gateway IP from routing table (fallback for Linux)
|
|
56
|
+
|
|
57
|
+
Returns:
|
|
58
|
+
The hostname or IP to use, or None if not in a container.
|
|
59
|
+
"""
|
|
60
|
+
# Check if we're in a container first
|
|
61
|
+
container_type = detect_container_environment()
|
|
62
|
+
if not container_type:
|
|
63
|
+
return None
|
|
64
|
+
|
|
65
|
+
# Try container-specific hostnames first based on detected type
|
|
66
|
+
if container_type == "podman":
|
|
67
|
+
# Podman: try host.containers.internal first
|
|
68
|
+
try:
|
|
69
|
+
socket.getaddrinfo("host.containers.internal", None)
|
|
70
|
+
except socket.gaierror:
|
|
71
|
+
pass
|
|
72
|
+
else:
|
|
73
|
+
return "host.containers.internal"
|
|
74
|
+
|
|
75
|
+
# Fallback to host.docker.internal (for Podman Desktop on macOS)
|
|
76
|
+
try:
|
|
77
|
+
socket.getaddrinfo("host.docker.internal", None)
|
|
78
|
+
except socket.gaierror:
|
|
79
|
+
pass
|
|
80
|
+
else:
|
|
81
|
+
return "host.docker.internal"
|
|
82
|
+
else:
|
|
83
|
+
# Docker: try host.docker.internal first
|
|
84
|
+
try:
|
|
85
|
+
socket.getaddrinfo("host.docker.internal", None)
|
|
86
|
+
except socket.gaierror:
|
|
87
|
+
pass
|
|
88
|
+
else:
|
|
89
|
+
return "host.docker.internal"
|
|
90
|
+
|
|
91
|
+
# Fallback to host.containers.internal (unlikely but possible)
|
|
92
|
+
try:
|
|
93
|
+
socket.getaddrinfo("host.containers.internal", None)
|
|
94
|
+
except socket.gaierror:
|
|
95
|
+
pass
|
|
96
|
+
else:
|
|
97
|
+
return "host.containers.internal"
|
|
98
|
+
|
|
99
|
+
# Fallback: try to get gateway IP from routing table (Linux containers)
|
|
100
|
+
try:
|
|
101
|
+
with Path("/proc/net/route").open() as f:
|
|
102
|
+
# Skip header
|
|
103
|
+
next(f)
|
|
104
|
+
for line in f:
|
|
105
|
+
fields = line.strip().split()
|
|
106
|
+
min_field_count = 3 # Minimum fields needed: interface, destination, gateway
|
|
107
|
+
if len(fields) >= min_field_count and fields[1] == "00000000": # Default route
|
|
108
|
+
# Gateway is in hex format (little-endian)
|
|
109
|
+
gateway_hex = fields[2]
|
|
110
|
+
# Convert little-endian hex to dotted IPv4
|
|
111
|
+
gw_int = int(gateway_hex, 16)
|
|
112
|
+
return socket.inet_ntoa(struct.pack("<L", gw_int))
|
|
113
|
+
except (FileNotFoundError, PermissionError, IndexError, ValueError):
|
|
114
|
+
pass
|
|
115
|
+
|
|
116
|
+
return None
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def transform_localhost_url(url: str | None) -> str | None:
|
|
120
|
+
"""Transform localhost URLs to container-accessible hosts when running in a container.
|
|
121
|
+
|
|
122
|
+
Automatically detects if running inside a container and finds the appropriate host
|
|
123
|
+
address to replace localhost/127.0.0.1. Tries in order:
|
|
124
|
+
- host.docker.internal (if resolvable)
|
|
125
|
+
- host.containers.internal (if resolvable)
|
|
126
|
+
- Gateway IP from routing table (fallback)
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
url: The original URL, can be None or empty string
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Transformed URL with container-accessible host if applicable, otherwise the original URL.
|
|
133
|
+
Returns None if url is None, empty string if url is empty string.
|
|
134
|
+
|
|
135
|
+
Example:
|
|
136
|
+
>>> transform_localhost_url("http://localhost:5001")
|
|
137
|
+
# Returns "http://host.docker.internal:5001" if running in Docker and hostname resolves
|
|
138
|
+
# Returns "http://172.17.0.1:5001" if running in Docker on Linux (gateway IP fallback)
|
|
139
|
+
# Returns "http://localhost:5001" if not in a container
|
|
140
|
+
>>> transform_localhost_url(None)
|
|
141
|
+
# Returns None
|
|
142
|
+
>>> transform_localhost_url("")
|
|
143
|
+
# Returns ""
|
|
144
|
+
"""
|
|
145
|
+
# Guard against None and empty string to prevent TypeError
|
|
146
|
+
if not url:
|
|
147
|
+
return url
|
|
148
|
+
|
|
149
|
+
container_host = get_container_host()
|
|
150
|
+
|
|
151
|
+
if not container_host:
|
|
152
|
+
return url
|
|
153
|
+
|
|
154
|
+
# Replace localhost and 127.0.0.1 with the container host
|
|
155
|
+
localhost_patterns = ["localhost", "127.0.0.1"]
|
|
156
|
+
|
|
157
|
+
for pattern in localhost_patterns:
|
|
158
|
+
if pattern in url:
|
|
159
|
+
return url.replace(pattern, container_host)
|
|
160
|
+
|
|
161
|
+
return url
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def unescape_string(s: str):
|
|
165
|
+
# Replace escaped new line characters with actual new line characters
|
|
166
|
+
return s.replace("\\n", "\n")
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def remove_ansi_escape_codes(text):
|
|
170
|
+
return re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", text)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def build_template_from_function(name: str, type_to_loader_dict: dict, *, add_function: bool = False):
|
|
174
|
+
classes = [item.__annotations__["return"].__name__ for item in type_to_loader_dict.values()]
|
|
175
|
+
|
|
176
|
+
# Raise error if name is not in chains
|
|
177
|
+
if name not in classes:
|
|
178
|
+
msg = f"{name} not found"
|
|
179
|
+
raise ValueError(msg)
|
|
180
|
+
|
|
181
|
+
for _type, v in type_to_loader_dict.items():
|
|
182
|
+
if v.__annotations__["return"].__name__ == name:
|
|
183
|
+
class_ = v.__annotations__["return"]
|
|
184
|
+
|
|
185
|
+
# Get the docstring
|
|
186
|
+
docs = parse(class_.__doc__)
|
|
187
|
+
|
|
188
|
+
variables = {"_type": _type}
|
|
189
|
+
for class_field_items, value in class_.model_fields.items():
|
|
190
|
+
if class_field_items == "callback_manager":
|
|
191
|
+
continue
|
|
192
|
+
variables[class_field_items] = {}
|
|
193
|
+
for name_, value_ in value.__repr_args__():
|
|
194
|
+
if name_ == "default_factory":
|
|
195
|
+
try:
|
|
196
|
+
variables[class_field_items]["default"] = get_default_factory(
|
|
197
|
+
module=class_.__base__.__module__, function=value_
|
|
198
|
+
)
|
|
199
|
+
except Exception: # noqa: BLE001
|
|
200
|
+
logger.debug(f"Error getting default factory for {value_}", exc_info=True)
|
|
201
|
+
variables[class_field_items]["default"] = None
|
|
202
|
+
elif name_ != "name":
|
|
203
|
+
variables[class_field_items][name_] = value_
|
|
204
|
+
|
|
205
|
+
variables[class_field_items]["placeholder"] = docs.params.get(class_field_items, "")
|
|
206
|
+
# Adding function to base classes to allow
|
|
207
|
+
# the output to be a function
|
|
208
|
+
base_classes = get_base_classes(class_)
|
|
209
|
+
if add_function:
|
|
210
|
+
base_classes.append("Callable")
|
|
211
|
+
|
|
212
|
+
return {
|
|
213
|
+
"template": format_dict(variables, name),
|
|
214
|
+
"description": docs.short_description or "",
|
|
215
|
+
"base_classes": base_classes,
|
|
216
|
+
}
|
|
217
|
+
return None
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def build_template_from_method(
|
|
221
|
+
class_name: str,
|
|
222
|
+
method_name: str,
|
|
223
|
+
type_to_cls_dict: dict,
|
|
224
|
+
*,
|
|
225
|
+
add_function: bool = False,
|
|
226
|
+
):
|
|
227
|
+
classes = [item.__name__ for item in type_to_cls_dict.values()]
|
|
228
|
+
|
|
229
|
+
# Raise error if class_name is not in classes
|
|
230
|
+
if class_name not in classes:
|
|
231
|
+
msg = f"{class_name} not found."
|
|
232
|
+
raise ValueError(msg)
|
|
233
|
+
|
|
234
|
+
for _type, v in type_to_cls_dict.items():
|
|
235
|
+
if v.__name__ == class_name:
|
|
236
|
+
class_ = v
|
|
237
|
+
|
|
238
|
+
# Check if the method exists in this class
|
|
239
|
+
if not hasattr(class_, method_name):
|
|
240
|
+
msg = f"Method {method_name} not found in class {class_name}"
|
|
241
|
+
raise ValueError(msg)
|
|
242
|
+
|
|
243
|
+
# Get the method
|
|
244
|
+
method = getattr(class_, method_name)
|
|
245
|
+
|
|
246
|
+
# Get the docstring
|
|
247
|
+
docs = parse(method.__doc__)
|
|
248
|
+
|
|
249
|
+
# Get the signature of the method
|
|
250
|
+
sig = inspect.signature(method)
|
|
251
|
+
|
|
252
|
+
# Get the parameters of the method
|
|
253
|
+
params = sig.parameters
|
|
254
|
+
|
|
255
|
+
# Initialize the variables dictionary with method parameters
|
|
256
|
+
variables = {
|
|
257
|
+
"_type": _type,
|
|
258
|
+
**{
|
|
259
|
+
name: {
|
|
260
|
+
"default": (param.default if param.default != param.empty else None),
|
|
261
|
+
"type": (param.annotation if param.annotation != param.empty else None),
|
|
262
|
+
"required": param.default == param.empty,
|
|
263
|
+
}
|
|
264
|
+
for name, param in params.items()
|
|
265
|
+
if name not in {"self", "kwargs", "args"}
|
|
266
|
+
},
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
base_classes = get_base_classes(class_)
|
|
270
|
+
|
|
271
|
+
# Adding function to base classes to allow the output to be a function
|
|
272
|
+
if add_function:
|
|
273
|
+
base_classes.append("Callable")
|
|
274
|
+
|
|
275
|
+
return {
|
|
276
|
+
"template": format_dict(variables, class_name),
|
|
277
|
+
"description": docs.short_description or "",
|
|
278
|
+
"base_classes": base_classes,
|
|
279
|
+
}
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def get_base_classes(cls):
|
|
284
|
+
"""Get the base classes of a class.
|
|
285
|
+
|
|
286
|
+
These are used to determine the output of the nodes.
|
|
287
|
+
"""
|
|
288
|
+
if hasattr(cls, "__bases__") and cls.__bases__:
|
|
289
|
+
bases = cls.__bases__
|
|
290
|
+
result = []
|
|
291
|
+
for base in bases:
|
|
292
|
+
if any(_type in base.__module__ for _type in ["pydantic", "abc"]):
|
|
293
|
+
continue
|
|
294
|
+
result.append(base.__name__)
|
|
295
|
+
base_classes = get_base_classes(base)
|
|
296
|
+
# check if the base_classes are in the result
|
|
297
|
+
# if not, add them
|
|
298
|
+
for base_class in base_classes:
|
|
299
|
+
if base_class not in result:
|
|
300
|
+
result.append(base_class)
|
|
301
|
+
else:
|
|
302
|
+
result = [cls.__name__]
|
|
303
|
+
if not result:
|
|
304
|
+
result = [cls.__name__]
|
|
305
|
+
return list({*result, cls.__name__})
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def get_default_factory(module: str, function: str):
|
|
309
|
+
pattern = r"<function (\w+)>"
|
|
310
|
+
|
|
311
|
+
if match := re.search(pattern, function):
|
|
312
|
+
import warnings
|
|
313
|
+
|
|
314
|
+
with warnings.catch_warnings():
|
|
315
|
+
warnings.filterwarnings(
|
|
316
|
+
"ignore", message="Support for class-based `config` is deprecated", category=DeprecationWarning
|
|
317
|
+
)
|
|
318
|
+
warnings.filterwarnings("ignore", message="Valid config keys have changed in V2", category=UserWarning)
|
|
319
|
+
imported_module = importlib.import_module(module)
|
|
320
|
+
return getattr(imported_module, match[1])()
|
|
321
|
+
return None
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def update_verbose(d: dict, *, new_value: bool) -> dict:
|
|
325
|
+
"""Recursively updates the value of the 'verbose' key in a dictionary.
|
|
326
|
+
|
|
327
|
+
Args:
|
|
328
|
+
d: the dictionary to update
|
|
329
|
+
new_value: the new value to set
|
|
330
|
+
|
|
331
|
+
Returns:
|
|
332
|
+
The updated dictionary.
|
|
333
|
+
"""
|
|
334
|
+
for k, v in d.items():
|
|
335
|
+
if isinstance(v, dict):
|
|
336
|
+
update_verbose(v, new_value=new_value)
|
|
337
|
+
elif k == "verbose":
|
|
338
|
+
d[k] = new_value
|
|
339
|
+
return d
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
def sync_to_async(func):
|
|
343
|
+
"""Decorator to convert a sync function to an async function."""
|
|
344
|
+
|
|
345
|
+
@wraps(func)
|
|
346
|
+
async def async_wrapper(*args, **kwargs):
|
|
347
|
+
return func(*args, **kwargs)
|
|
348
|
+
|
|
349
|
+
return async_wrapper
|
|
350
|
+
|
|
351
|
+
|
|
352
|
+
def format_dict(dictionary: dict[str, Any], class_name: str | None = None) -> dict[str, Any]:
|
|
353
|
+
"""Formats a dictionary by removing certain keys and modifying the values of other keys.
|
|
354
|
+
|
|
355
|
+
Returns:
|
|
356
|
+
A new dictionary with the desired modifications applied.
|
|
357
|
+
"""
|
|
358
|
+
for key, value in dictionary.items():
|
|
359
|
+
if key == "_type":
|
|
360
|
+
continue
|
|
361
|
+
|
|
362
|
+
type_: str | type = get_type(value)
|
|
363
|
+
|
|
364
|
+
if "BaseModel" in str(type_):
|
|
365
|
+
continue
|
|
366
|
+
|
|
367
|
+
type_ = remove_optional_wrapper(type_)
|
|
368
|
+
type_ = check_list_type(type_, value)
|
|
369
|
+
type_ = replace_mapping_with_dict(type_)
|
|
370
|
+
type_ = get_type_from_union_literal(type_)
|
|
371
|
+
|
|
372
|
+
value["type"] = get_formatted_type(key, type_)
|
|
373
|
+
value["show"] = should_show_field(value, key)
|
|
374
|
+
value["password"] = is_password_field(key)
|
|
375
|
+
value["multiline"] = is_multiline_field(key)
|
|
376
|
+
|
|
377
|
+
if key == "dict_":
|
|
378
|
+
set_dict_file_attributes(value)
|
|
379
|
+
|
|
380
|
+
replace_default_value_with_actual(value)
|
|
381
|
+
|
|
382
|
+
if key == "headers":
|
|
383
|
+
set_headers_value(value)
|
|
384
|
+
|
|
385
|
+
add_options_to_field(value, class_name, key)
|
|
386
|
+
|
|
387
|
+
return dictionary
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
# "Union[Literal['f-string'], Literal['jinja2']]" -> "str"
|
|
391
|
+
def get_type_from_union_literal(union_literal: str) -> str:
|
|
392
|
+
# if types are literal strings
|
|
393
|
+
# the type is a string
|
|
394
|
+
if "Literal" in union_literal:
|
|
395
|
+
return "str"
|
|
396
|
+
return union_literal
|
|
397
|
+
|
|
398
|
+
|
|
399
|
+
def get_type(value: Any) -> str | type:
|
|
400
|
+
"""Retrieves the type value from the dictionary.
|
|
401
|
+
|
|
402
|
+
Returns:
|
|
403
|
+
The type value.
|
|
404
|
+
"""
|
|
405
|
+
# get "type" or "annotation" from the value
|
|
406
|
+
type_ = value.get("type") or value.get("annotation")
|
|
407
|
+
|
|
408
|
+
return type_ if isinstance(type_, str) else type_.__name__
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def remove_optional_wrapper(type_: str | type) -> str:
|
|
412
|
+
"""Removes the 'Optional' wrapper from the type string.
|
|
413
|
+
|
|
414
|
+
Returns:
|
|
415
|
+
The type string with the 'Optional' wrapper removed.
|
|
416
|
+
"""
|
|
417
|
+
if isinstance(type_, type):
|
|
418
|
+
type_ = str(type_)
|
|
419
|
+
if "Optional" in type_:
|
|
420
|
+
type_ = type_.replace("Optional[", "")[:-1]
|
|
421
|
+
|
|
422
|
+
return type_
|
|
423
|
+
|
|
424
|
+
|
|
425
|
+
def check_list_type(type_: str, value: dict[str, Any]) -> str:
|
|
426
|
+
"""Checks if the type is a list type and modifies the value accordingly.
|
|
427
|
+
|
|
428
|
+
Returns:
|
|
429
|
+
The modified type string.
|
|
430
|
+
"""
|
|
431
|
+
if any(list_type in type_ for list_type in ["List", "Sequence", "Set"]):
|
|
432
|
+
type_ = type_.replace("List[", "").replace("Sequence[", "").replace("Set[", "")[:-1]
|
|
433
|
+
value["list"] = True
|
|
434
|
+
else:
|
|
435
|
+
value["list"] = False
|
|
436
|
+
|
|
437
|
+
return type_
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def replace_mapping_with_dict(type_: str) -> str:
|
|
441
|
+
"""Replaces 'Mapping' with 'dict' in the type string.
|
|
442
|
+
|
|
443
|
+
Returns:
|
|
444
|
+
The modified type string.
|
|
445
|
+
"""
|
|
446
|
+
if "Mapping" in type_:
|
|
447
|
+
type_ = type_.replace("Mapping", "dict")
|
|
448
|
+
|
|
449
|
+
return type_
|
|
450
|
+
|
|
451
|
+
|
|
452
|
+
def get_formatted_type(key: str, type_: str) -> str:
|
|
453
|
+
"""Formats the type value based on the given key.
|
|
454
|
+
|
|
455
|
+
Returns:
|
|
456
|
+
The formatted type value.
|
|
457
|
+
"""
|
|
458
|
+
if key == "allowed_tools":
|
|
459
|
+
return "Tool"
|
|
460
|
+
|
|
461
|
+
if key == "max_value_length":
|
|
462
|
+
return "int"
|
|
463
|
+
|
|
464
|
+
return type_
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
def should_show_field(value: dict[str, Any], key: str) -> bool:
|
|
468
|
+
"""Determines if the field should be shown or not.
|
|
469
|
+
|
|
470
|
+
Returns:
|
|
471
|
+
True if the field should be shown, False otherwise.
|
|
472
|
+
"""
|
|
473
|
+
return (
|
|
474
|
+
(value["required"] and key != "input_variables")
|
|
475
|
+
or key in FORCE_SHOW_FIELDS
|
|
476
|
+
or any(text in key.lower() for text in ["password", "token", "api", "key"])
|
|
477
|
+
)
|
|
478
|
+
|
|
479
|
+
|
|
480
|
+
def is_password_field(key: str) -> bool:
|
|
481
|
+
"""Determines if the field is a password field.
|
|
482
|
+
|
|
483
|
+
Returns:
|
|
484
|
+
True if the field is a password field, False otherwise.
|
|
485
|
+
"""
|
|
486
|
+
return any(text in key.lower() for text in ["password", "token", "api", "key"])
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
def is_multiline_field(key: str) -> bool:
|
|
490
|
+
"""Determines if the field is a multiline field.
|
|
491
|
+
|
|
492
|
+
Returns:
|
|
493
|
+
True if the field is a multiline field, False otherwise.
|
|
494
|
+
"""
|
|
495
|
+
return key in {
|
|
496
|
+
"suffix",
|
|
497
|
+
"prefix",
|
|
498
|
+
"template",
|
|
499
|
+
"examples",
|
|
500
|
+
"code",
|
|
501
|
+
"headers",
|
|
502
|
+
"format_instructions",
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
|
|
506
|
+
def set_dict_file_attributes(value: dict[str, Any]) -> None:
|
|
507
|
+
"""Sets the file attributes for the 'dict_' key."""
|
|
508
|
+
value["type"] = "file"
|
|
509
|
+
value["fileTypes"] = [".json", ".yaml", ".yml"]
|
|
510
|
+
|
|
511
|
+
|
|
512
|
+
def replace_default_value_with_actual(value: dict[str, Any]) -> None:
|
|
513
|
+
"""Replaces the default value with the actual value."""
|
|
514
|
+
if "default" in value:
|
|
515
|
+
value["value"] = value["default"]
|
|
516
|
+
value.pop("default")
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
def set_headers_value(value: dict[str, Any]) -> None:
|
|
520
|
+
"""Sets the value for the 'headers' key."""
|
|
521
|
+
value["value"] = """{"Authorization": "Bearer <token>"}"""
|
|
522
|
+
|
|
523
|
+
|
|
524
|
+
def add_options_to_field(value: dict[str, Any], class_name: str | None, key: str) -> None:
|
|
525
|
+
"""Adds options to the field based on the class name and key."""
|
|
526
|
+
options_map = {
|
|
527
|
+
"OpenAI": constants.OPENAI_MODELS,
|
|
528
|
+
"ChatOpenAI": constants.CHAT_OPENAI_MODELS,
|
|
529
|
+
"ReasoningOpenAI": constants.REASONING_OPENAI_MODELS,
|
|
530
|
+
"Anthropic": constants.ANTHROPIC_MODELS,
|
|
531
|
+
"ChatAnthropic": constants.ANTHROPIC_MODELS,
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
if class_name in options_map and key == "model_name":
|
|
535
|
+
value["options"] = options_map[class_name]
|
|
536
|
+
value["list"] = True
|
|
537
|
+
value["value"] = options_map[class_name][0]
|
|
538
|
+
|
|
539
|
+
|
|
540
|
+
def build_loader_repr_from_data(data: list[Data]) -> str:
|
|
541
|
+
"""Builds a string representation of the loader based on the given data.
|
|
542
|
+
|
|
543
|
+
Args:
|
|
544
|
+
data (List[Data]): A list of data.
|
|
545
|
+
|
|
546
|
+
Returns:
|
|
547
|
+
str: A string representation of the loader.
|
|
548
|
+
|
|
549
|
+
"""
|
|
550
|
+
if data:
|
|
551
|
+
avg_length = sum(len(doc.text) for doc in data) / len(data)
|
|
552
|
+
return f"""{len(data)} data
|
|
553
|
+
\nAvg. Data Length (characters): {int(avg_length)}
|
|
554
|
+
Data: {data[:3]}..."""
|
|
555
|
+
return "0 data"
|
|
556
|
+
|
|
557
|
+
|
|
558
|
+
async def update_settings(
|
|
559
|
+
*,
|
|
560
|
+
config: str | None = None,
|
|
561
|
+
cache: str | None = None,
|
|
562
|
+
dev: bool = False,
|
|
563
|
+
remove_api_keys: bool = False,
|
|
564
|
+
components_path: Path | None = None,
|
|
565
|
+
store: bool = True,
|
|
566
|
+
auto_saving: bool = True,
|
|
567
|
+
auto_saving_interval: int = 1000,
|
|
568
|
+
health_check_max_retries: int = 5,
|
|
569
|
+
max_file_size_upload: int = 100,
|
|
570
|
+
webhook_polling_interval: int = 5000,
|
|
571
|
+
) -> None:
|
|
572
|
+
"""Update the settings from a config file."""
|
|
573
|
+
# Check for database_url in the environment variables
|
|
574
|
+
|
|
575
|
+
settings_service = get_settings_service()
|
|
576
|
+
if not settings_service:
|
|
577
|
+
msg = "Settings service not found"
|
|
578
|
+
raise RuntimeError(msg)
|
|
579
|
+
|
|
580
|
+
if config:
|
|
581
|
+
await logger.adebug(f"Loading settings from {config}")
|
|
582
|
+
await settings_service.settings.update_from_yaml(config, dev=dev)
|
|
583
|
+
if remove_api_keys:
|
|
584
|
+
await logger.adebug(f"Setting remove_api_keys to {remove_api_keys}")
|
|
585
|
+
settings_service.settings.update_settings(remove_api_keys=remove_api_keys)
|
|
586
|
+
if cache:
|
|
587
|
+
await logger.adebug(f"Setting cache to {cache}")
|
|
588
|
+
settings_service.settings.update_settings(cache=cache)
|
|
589
|
+
if components_path:
|
|
590
|
+
await logger.adebug(f"Adding component path {components_path}")
|
|
591
|
+
settings_service.settings.update_settings(components_path=components_path)
|
|
592
|
+
if not store:
|
|
593
|
+
logger.debug("Setting store to False")
|
|
594
|
+
settings_service.settings.update_settings(store=False)
|
|
595
|
+
if not auto_saving:
|
|
596
|
+
logger.debug("Setting auto_saving to False")
|
|
597
|
+
settings_service.settings.update_settings(auto_saving=False)
|
|
598
|
+
if auto_saving_interval is not None:
|
|
599
|
+
logger.debug(f"Setting auto_saving_interval to {auto_saving_interval}")
|
|
600
|
+
settings_service.settings.update_settings(auto_saving_interval=auto_saving_interval)
|
|
601
|
+
if health_check_max_retries is not None:
|
|
602
|
+
logger.debug(f"Setting health_check_max_retries to {health_check_max_retries}")
|
|
603
|
+
settings_service.settings.update_settings(health_check_max_retries=health_check_max_retries)
|
|
604
|
+
if max_file_size_upload is not None:
|
|
605
|
+
logger.debug(f"Setting max_file_size_upload to {max_file_size_upload}")
|
|
606
|
+
settings_service.settings.update_settings(max_file_size_upload=max_file_size_upload)
|
|
607
|
+
if webhook_polling_interval is not None:
|
|
608
|
+
logger.debug(f"Setting webhook_polling_interval to {webhook_polling_interval}")
|
|
609
|
+
settings_service.settings.update_settings(webhook_polling_interval=webhook_polling_interval)
|
|
610
|
+
|
|
611
|
+
|
|
612
|
+
def is_class_method(func, cls):
|
|
613
|
+
"""Check if a function is a class method."""
|
|
614
|
+
return inspect.ismethod(func) and func.__self__ is cls.__class__
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
def escape_json_dump(edge_dict):
|
|
618
|
+
return json.dumps(edge_dict).replace('"', "œ")
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
def find_closest_match(string: str, list_of_strings: list[str]) -> str | None:
|
|
622
|
+
"""Find the closest match in a list of strings."""
|
|
623
|
+
closest_match = difflib.get_close_matches(string, list_of_strings, n=1, cutoff=0.2)
|
|
624
|
+
if closest_match:
|
|
625
|
+
return closest_match[0]
|
|
626
|
+
return None
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
from lfx.serialization import constants
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def truncate_long_strings(data, max_length=None):
|
|
5
|
+
"""Recursively traverse the dictionary or list and truncate strings longer than max_length.
|
|
6
|
+
|
|
7
|
+
Returns:
|
|
8
|
+
The data with strings truncated if they exceed the max length.
|
|
9
|
+
"""
|
|
10
|
+
if max_length is None:
|
|
11
|
+
max_length = constants.MAX_TEXT_LENGTH
|
|
12
|
+
|
|
13
|
+
if max_length < 0:
|
|
14
|
+
return data
|
|
15
|
+
|
|
16
|
+
if not isinstance(data, dict | list):
|
|
17
|
+
if isinstance(data, str) and len(data) > max_length:
|
|
18
|
+
return data[:max_length] + "..."
|
|
19
|
+
return data
|
|
20
|
+
|
|
21
|
+
if isinstance(data, dict):
|
|
22
|
+
for key, value in data.items():
|
|
23
|
+
if isinstance(value, str) and len(value) > max_length:
|
|
24
|
+
data[key] = value[:max_length] + "..."
|
|
25
|
+
elif isinstance(value, (dict | list)):
|
|
26
|
+
truncate_long_strings(value, max_length)
|
|
27
|
+
elif isinstance(data, list):
|
|
28
|
+
for index, item in enumerate(data):
|
|
29
|
+
if isinstance(item, str) and len(item) > max_length:
|
|
30
|
+
data[index] = item[:max_length] + "..."
|
|
31
|
+
elif isinstance(item, (dict | list)):
|
|
32
|
+
truncate_long_strings(item, max_length)
|
|
33
|
+
|
|
34
|
+
return data
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def is_valid_database_url(url: str) -> bool:
|
|
38
|
+
"""Validate database connection URLs compatible with SQLAlchemy.
|
|
39
|
+
|
|
40
|
+
Args:
|
|
41
|
+
url (str): Database connection URL to validate
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
bool: True if URL is valid, False otherwise
|
|
45
|
+
"""
|
|
46
|
+
try:
|
|
47
|
+
from sqlalchemy.engine import make_url
|
|
48
|
+
|
|
49
|
+
parsed_url = make_url(url)
|
|
50
|
+
parsed_url.get_dialect()
|
|
51
|
+
parsed_url.get_driver_name()
|
|
52
|
+
|
|
53
|
+
except Exception: # noqa: BLE001
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
return True
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""Cloud environment validation utilities.
|
|
2
|
+
|
|
3
|
+
This module contains validation functions for cloud-specific constraints,
|
|
4
|
+
such as disabling certain features when running in Astra cloud environment.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import os
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def raise_error_if_astra_cloud_disable_component(msg: str):
|
|
11
|
+
"""Validate that we're not in an Astra cloud environment and certain components/features need to be disabled.
|
|
12
|
+
|
|
13
|
+
Check if the environment variable ASTRA_CLOUD_DISABLE_COMPONENT is set to true.
|
|
14
|
+
IF it is, then we know we are in an Astra cloud environment and
|
|
15
|
+
that certain components or component-features need to be disabled.
|
|
16
|
+
|
|
17
|
+
Args:
|
|
18
|
+
msg: The error message to raise if we're in an Astra cloud environment.
|
|
19
|
+
|
|
20
|
+
Raises:
|
|
21
|
+
ValueError: If running in an Astra cloud environment.
|
|
22
|
+
"""
|
|
23
|
+
if (
|
|
24
|
+
disable_component := os.getenv("ASTRA_CLOUD_DISABLE_COMPONENT", "false")
|
|
25
|
+
) and disable_component.lower().strip() == "true":
|
|
26
|
+
raise ValueError(msg)
|