lfx-nightly 0.1.11.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- lfx/__init__.py +0 -0
- lfx/__main__.py +25 -0
- lfx/base/__init__.py +0 -0
- lfx/base/agents/__init__.py +0 -0
- lfx/base/agents/agent.py +268 -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 +346 -0
- lfx/base/agents/utils.py +205 -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 +1291 -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 +685 -0
- lfx/base/data/docling_utils.py +245 -0
- lfx/base/data/utils.py +198 -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/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 +20 -0
- lfx/base/io/text.py +22 -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 +1398 -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 +47 -0
- lfx/base/models/aws_constants.py +151 -0
- lfx/base/models/chat_result.py +76 -0
- lfx/base/models/google_generative_ai_constants.py +70 -0
- lfx/base/models/groq_constants.py +134 -0
- lfx/base/models/model.py +375 -0
- lfx/base/models/model_input_constants.py +307 -0
- lfx/base/models/model_metadata.py +41 -0
- lfx/base/models/model_utils.py +8 -0
- lfx/base/models/novita_constants.py +35 -0
- lfx/base/models/ollama_constants.py +49 -0
- lfx/base/models/openai_constants.py +122 -0
- lfx/base/models/sambanova_constants.py +18 -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 +224 -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 +319 -0
- lfx/cli/common.py +650 -0
- lfx/cli/run.py +441 -0
- lfx/cli/script_loader.py +247 -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 +411 -0
- lfx/components/_importing.py +42 -0
- lfx/components/agentql/__init__.py +3 -0
- lfx/components/agentql/agentql_api.py +151 -0
- lfx/components/agents/__init__.py +34 -0
- lfx/components/agents/agent.py +558 -0
- lfx/components/agents/mcp_component.py +501 -0
- lfx/components/aiml/__init__.py +37 -0
- lfx/components/aiml/aiml.py +112 -0
- lfx/components/aiml/aiml_embeddings.py +37 -0
- lfx/components/amazon/__init__.py +36 -0
- lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
- lfx/components/amazon/amazon_bedrock_model.py +124 -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 +163 -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 +167 -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/composio/__init__.py +74 -0
- lfx/components/composio/composio_api.py +268 -0
- lfx/components/composio/dropbox_compnent.py +11 -0
- lfx/components/composio/github_composio.py +11 -0
- lfx/components/composio/gmail_composio.py +38 -0
- lfx/components/composio/googlecalendar_composio.py +11 -0
- lfx/components/composio/googlemeet_composio.py +11 -0
- lfx/components/composio/googletasks_composio.py +8 -0
- lfx/components/composio/linear_composio.py +11 -0
- lfx/components/composio/outlook_composio.py +11 -0
- lfx/components/composio/reddit_composio.py +11 -0
- lfx/components/composio/slack_composio.py +582 -0
- lfx/components/composio/slackbot_composio.py +11 -0
- lfx/components/composio/supabase_composio.py +11 -0
- lfx/components/composio/todoist_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 +107 -0
- lfx/components/crewai/hierarchical_crew.py +46 -0
- lfx/components/crewai/hierarchical_task.py +44 -0
- lfx/components/crewai/sequential_crew.py +52 -0
- lfx/components/crewai/sequential_task.py +73 -0
- lfx/components/crewai/sequential_task_agent.py +143 -0
- lfx/components/custom_component/__init__.py +34 -0
- lfx/components/custom_component/custom_component.py +31 -0
- lfx/components/data/__init__.py +64 -0
- lfx/components/data/api_request.py +544 -0
- lfx/components/data/csv_to_data.py +95 -0
- lfx/components/data/directory.py +113 -0
- lfx/components/data/file.py +577 -0
- lfx/components/data/json_to_data.py +98 -0
- lfx/components/data/news_search.py +164 -0
- lfx/components/data/rss.py +69 -0
- lfx/components/data/sql_executor.py +101 -0
- lfx/components/data/url.py +311 -0
- lfx/components/data/web_search.py +112 -0
- lfx/components/data/webhook.py +56 -0
- lfx/components/datastax/__init__.py +70 -0
- lfx/components/datastax/astra_assistant_manager.py +306 -0
- lfx/components/datastax/astra_db.py +75 -0
- lfx/components/datastax/astra_vectorize.py +124 -0
- lfx/components/datastax/astradb.py +1285 -0
- lfx/components/datastax/astradb_cql.py +314 -0
- lfx/components/datastax/astradb_graph.py +330 -0
- lfx/components/datastax/astradb_tool.py +414 -0
- lfx/components/datastax/astradb_vectorstore.py +1285 -0
- lfx/components/datastax/cassandra.py +92 -0
- lfx/components/datastax/create_assistant.py +58 -0
- lfx/components/datastax/create_thread.py +32 -0
- lfx/components/datastax/dotenv.py +35 -0
- lfx/components/datastax/get_assistant.py +37 -0
- lfx/components/datastax/getenvvar.py +30 -0
- lfx/components/datastax/graph_rag.py +141 -0
- lfx/components/datastax/hcd.py +314 -0
- lfx/components/datastax/list_assistants.py +25 -0
- lfx/components/datastax/run.py +89 -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 +231 -0
- lfx/components/docling/docling_remote.py +193 -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 +243 -0
- lfx/components/embeddings/__init__.py +37 -0
- lfx/components/embeddings/similarity.py +76 -0
- lfx/components/embeddings/text_embedder.py +64 -0
- lfx/components/exa/__init__.py +3 -0
- lfx/components/exa/exa_search.py +68 -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/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 +192 -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 +147 -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 +136 -0
- lfx/components/helpers/__init__.py +52 -0
- lfx/components/helpers/calculator_core.py +89 -0
- lfx/components/helpers/create_list.py +40 -0
- lfx/components/helpers/current_date.py +42 -0
- lfx/components/helpers/id_generator.py +42 -0
- lfx/components/helpers/memory.py +251 -0
- lfx/components/helpers/output_parser.py +45 -0
- lfx/components/helpers/store_message.py +90 -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 +197 -0
- lfx/components/huggingface/huggingface_inference_api.py +106 -0
- lfx/components/ibm/__init__.py +34 -0
- lfx/components/ibm/watsonx.py +203 -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 +38 -0
- lfx/components/input_output/chat.py +120 -0
- lfx/components/input_output/chat_output.py +200 -0
- lfx/components/input_output/text.py +27 -0
- lfx/components/input_output/text_output.py +29 -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/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 +107 -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 +45 -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/lmstudio/__init__.py +34 -0
- lfx/components/lmstudio/lmstudioembeddings.py +89 -0
- lfx/components/lmstudio/lmstudiomodel.py +129 -0
- lfx/components/logic/__init__.py +52 -0
- lfx/components/logic/conditional_router.py +171 -0
- lfx/components/logic/data_conditional_router.py +125 -0
- lfx/components/logic/flow_tool.py +110 -0
- lfx/components/logic/listen.py +29 -0
- lfx/components/logic/loop.py +125 -0
- lfx/components/logic/notify.py +88 -0
- lfx/components/logic/pass_message.py +35 -0
- lfx/components/logic/run_flow.py +71 -0
- lfx/components/logic/sub_flow.py +114 -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 +136 -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 +34 -0
- lfx/components/models/embedding_model.py +114 -0
- lfx/components/models/language_model.py +144 -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 +157 -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 +330 -0
- lfx/components/ollama/ollama_embeddings.py +106 -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 +202 -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 +117 -0
- lfx/components/processing/alter_metadata.py +108 -0
- lfx/components/processing/batch_run.py +205 -0
- lfx/components/processing/combine_text.py +39 -0
- lfx/components/processing/converter.py +159 -0
- lfx/components/processing/create_data.py +110 -0
- lfx/components/processing/data_operations.py +438 -0
- lfx/components/processing/data_to_dataframe.py +70 -0
- lfx/components/processing/dataframe_operations.py +313 -0
- lfx/components/processing/extract_key.py +53 -0
- lfx/components/processing/filter_data.py +42 -0
- lfx/components/processing/filter_data_values.py +88 -0
- lfx/components/processing/json_cleaner.py +103 -0
- lfx/components/processing/lambda_filter.py +154 -0
- lfx/components/processing/llm_router.py +499 -0
- lfx/components/processing/merge_data.py +90 -0
- lfx/components/processing/message_to_data.py +36 -0
- lfx/components/processing/parse_data.py +70 -0
- lfx/components/processing/parse_dataframe.py +68 -0
- lfx/components/processing/parse_json_data.py +90 -0
- lfx/components/processing/parser.py +143 -0
- lfx/components/processing/prompt.py +67 -0
- lfx/components/processing/python_repl_core.py +98 -0
- lfx/components/processing/regex.py +82 -0
- lfx/components/processing/save_file.py +225 -0
- lfx/components/processing/select_data.py +48 -0
- lfx/components/processing/split_text.py +141 -0
- lfx/components/processing/structured_output.py +202 -0
- lfx/components/processing/update_data.py +160 -0
- lfx/components/prototypes/__init__.py +34 -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 +72 -0
- lfx/components/tools/calculator.py +108 -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 +327 -0
- lfx/components/tools/python_repl.py +97 -0
- lfx/components/tools/search_api.py +87 -0
- lfx/components/tools/searxng.py +145 -0
- lfx/components/tools/serp_api.py +119 -0
- lfx/components/tools/tavily_search_tool.py +344 -0
- lfx/components/tools/wikidata_api.py +102 -0
- lfx/components/tools/wikipedia_api.py +49 -0
- lfx/components/tools/yahoo_finance.py +129 -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 +291 -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 +179 -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/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 +40 -0
- lfx/components/vectorstores/astradb.py +1285 -0
- lfx/components/vectorstores/astradb_graph.py +319 -0
- lfx/components/vectorstores/cassandra.py +264 -0
- lfx/components/vectorstores/cassandra_graph.py +238 -0
- lfx/components/vectorstores/chroma.py +167 -0
- lfx/components/vectorstores/clickhouse.py +135 -0
- lfx/components/vectorstores/couchbase.py +102 -0
- lfx/components/vectorstores/elasticsearch.py +267 -0
- lfx/components/vectorstores/faiss.py +111 -0
- lfx/components/vectorstores/graph_rag.py +141 -0
- lfx/components/vectorstores/hcd.py +314 -0
- lfx/components/vectorstores/local_db.py +261 -0
- lfx/components/vectorstores/milvus.py +115 -0
- lfx/components/vectorstores/mongodb_atlas.py +213 -0
- lfx/components/vectorstores/opensearch.py +243 -0
- lfx/components/vectorstores/pgvector.py +72 -0
- lfx/components/vectorstores/pinecone.py +134 -0
- lfx/components/vectorstores/qdrant.py +109 -0
- lfx/components/vectorstores/supabase.py +76 -0
- lfx/components/vectorstores/upstash.py +124 -0
- lfx/components/vectorstores/vectara.py +97 -0
- lfx/components/vectorstores/vectara_rag.py +164 -0
- lfx/components/vectorstores/weaviate.py +89 -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/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 +118 -0
- lfx/components/zep/__init__.py +3 -0
- lfx/components/zep/zep.py +44 -0
- lfx/constants.py +6 -0
- lfx/custom/__init__.py +7 -0
- lfx/custom/attributes.py +86 -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 +1808 -0
- lfx/custom/custom_component/component_with_cache.py +8 -0
- lfx/custom/custom_component/custom_component.py +588 -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 +488 -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 +215 -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 +277 -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 +2238 -0
- lfx/graph/graph/constants.py +63 -0
- lfx/graph/graph/runnable_vertices_manager.py +133 -0
- lfx/graph/graph/schema.py +52 -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 +237 -0
- lfx/graph/utils.py +200 -0
- lfx/graph/vertex/__init__.py +0 -0
- lfx/graph/vertex/base.py +823 -0
- lfx/graph/vertex/constants.py +0 -0
- lfx/graph/vertex/exceptions.py +4 -0
- lfx/graph/vertex/param_handler.py +264 -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 +1 -0
- lfx/helpers/base_model.py +71 -0
- lfx/helpers/custom.py +13 -0
- lfx/helpers/data.py +167 -0
- lfx/helpers/flow.py +194 -0
- lfx/inputs/__init__.py +68 -0
- lfx/inputs/constants.py +2 -0
- lfx/inputs/input_mixin.py +328 -0
- lfx/inputs/inputs.py +714 -0
- lfx/inputs/validators.py +19 -0
- lfx/interface/__init__.py +6 -0
- lfx/interface/components.py +489 -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 +224 -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 +289 -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 +385 -0
- lfx/memory/__init__.py +90 -0
- lfx/memory/stubs.py +283 -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/data.py +308 -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 +131 -0
- lfx/schema/json_schema.py +141 -0
- lfx/schema/log.py +61 -0
- lfx/schema/message.py +473 -0
- lfx/schema/openai_responses_schemas.py +74 -0
- lfx/schema/properties.py +41 -0
- lfx/schema/schema.py +171 -0
- lfx/schema/serialize.py +13 -0
- lfx/schema/table.py +140 -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 +23 -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/deps.py +129 -0
- lfx/services/factory.py +19 -0
- lfx/services/initialize.py +19 -0
- lfx/services/interfaces.py +103 -0
- lfx/services/manager.py +172 -0
- lfx/services/schema.py +20 -0
- lfx/services/session.py +82 -0
- lfx/services/settings/__init__.py +3 -0
- lfx/services/settings/auth.py +130 -0
- lfx/services/settings/base.py +539 -0
- lfx/services/settings/constants.py +31 -0
- lfx/services/settings/factory.py +23 -0
- lfx/services/settings/feature_flags.py +12 -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 +155 -0
- lfx/services/storage/service.py +54 -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 +257 -0
- lfx/template/field/prompt.py +15 -0
- lfx/template/frontend_node/__init__.py +6 -0
- lfx/template/frontend_node/base.py +212 -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 +205 -0
- lfx/utils/data_structure.py +212 -0
- lfx/utils/exceptions.py +22 -0
- lfx/utils/helpers.py +28 -0
- lfx/utils/image.py +73 -0
- lfx/utils/lazy_load.py +15 -0
- lfx/utils/request_utils.py +18 -0
- lfx/utils/schemas.py +139 -0
- lfx/utils/util.py +481 -0
- lfx/utils/util_strings.py +56 -0
- lfx/utils/version.py +24 -0
- lfx_nightly-0.1.11.dev0.dist-info/METADATA +293 -0
- lfx_nightly-0.1.11.dev0.dist-info/RECORD +699 -0
- lfx_nightly-0.1.11.dev0.dist-info/WHEEL +4 -0
- lfx_nightly-0.1.11.dev0.dist-info/entry_points.txt +2 -0
lfx/cli/run.py
ADDED
@@ -0,0 +1,441 @@
|
|
1
|
+
import json
|
2
|
+
import sys
|
3
|
+
import tempfile
|
4
|
+
from functools import partial
|
5
|
+
from io import StringIO
|
6
|
+
from pathlib import Path
|
7
|
+
|
8
|
+
import typer
|
9
|
+
from asyncer import syncify
|
10
|
+
|
11
|
+
from lfx.cli.script_loader import (
|
12
|
+
extract_structured_result,
|
13
|
+
extract_text_from_result,
|
14
|
+
find_graph_variable,
|
15
|
+
load_graph_from_script,
|
16
|
+
)
|
17
|
+
from lfx.cli.validation import validate_global_variables_for_env
|
18
|
+
from lfx.log.logger import logger
|
19
|
+
from lfx.schema.schema import InputValueRequest
|
20
|
+
|
21
|
+
|
22
|
+
def output_error(error_message: str, *, verbose: bool) -> None:
|
23
|
+
"""Output error in JSON format to stdout when not verbose, or to stderr when verbose."""
|
24
|
+
if verbose:
|
25
|
+
typer.echo(f"{error_message}", file=sys.stderr)
|
26
|
+
else:
|
27
|
+
error_response = {
|
28
|
+
"success": False,
|
29
|
+
"error": error_message,
|
30
|
+
"type": "error",
|
31
|
+
}
|
32
|
+
typer.echo(json.dumps(error_response))
|
33
|
+
|
34
|
+
|
35
|
+
@partial(syncify, raise_sync_error=False)
|
36
|
+
async def run(
|
37
|
+
script_path: Path | None = typer.Argument( # noqa: B008
|
38
|
+
None, help="Path to the Python script (.py) or JSON flow (.json) containing a graph"
|
39
|
+
),
|
40
|
+
input_value: str | None = typer.Argument(None, help="Input value to pass to the graph"),
|
41
|
+
input_value_option: str | None = typer.Option(
|
42
|
+
None,
|
43
|
+
"--input-value",
|
44
|
+
help="Input value to pass to the graph (alternative to positional argument)",
|
45
|
+
),
|
46
|
+
output_format: str = typer.Option(
|
47
|
+
"json",
|
48
|
+
"--format",
|
49
|
+
"-f",
|
50
|
+
help="Output format: json, text, message, or result",
|
51
|
+
),
|
52
|
+
flow_json: str | None = typer.Option(
|
53
|
+
None,
|
54
|
+
"--flow-json",
|
55
|
+
help=("Inline JSON flow content as a string (alternative to script_path)"),
|
56
|
+
),
|
57
|
+
*,
|
58
|
+
stdin: bool | None = typer.Option(
|
59
|
+
default=False,
|
60
|
+
flag_value="--stdin",
|
61
|
+
show_default=True,
|
62
|
+
help="Read JSON flow content from stdin (alternative to script_path)",
|
63
|
+
),
|
64
|
+
check_variables: bool = typer.Option(
|
65
|
+
default=True,
|
66
|
+
show_default=True,
|
67
|
+
help="Check global variables for environment compatibility",
|
68
|
+
),
|
69
|
+
verbose: bool = typer.Option(
|
70
|
+
default=False,
|
71
|
+
show_default=True,
|
72
|
+
help="Show diagnostic output and execution details",
|
73
|
+
),
|
74
|
+
timing: bool = typer.Option(
|
75
|
+
default=False,
|
76
|
+
show_default=True,
|
77
|
+
help="Include detailed timing information in output",
|
78
|
+
),
|
79
|
+
) -> None:
|
80
|
+
"""Execute a Langflow graph script or JSON flow and return the result.
|
81
|
+
|
82
|
+
This command analyzes and executes either a Python script containing a Langflow graph,
|
83
|
+
a JSON flow file, inline JSON, or JSON from stdin, returning the result in the specified format.
|
84
|
+
By default, output is minimal for use in containers and serverless environments.
|
85
|
+
|
86
|
+
Args:
|
87
|
+
script_path: Path to the Python script (.py) or JSON flow (.json) containing a graph
|
88
|
+
input_value: Input value to pass to the graph (positional argument)
|
89
|
+
input_value_option: Input value to pass to the graph (alternative option)
|
90
|
+
verbose: Show diagnostic output and execution details
|
91
|
+
output_format: Format for output (json, text, message, or result)
|
92
|
+
flow_json: Inline JSON flow content as a string
|
93
|
+
stdin: Read JSON flow content from stdin
|
94
|
+
check_variables: Check global variables for environment compatibility
|
95
|
+
timing: Include detailed timing information in output
|
96
|
+
"""
|
97
|
+
# Start timing if requested
|
98
|
+
import time
|
99
|
+
from datetime import datetime
|
100
|
+
|
101
|
+
def verbose_print(message: str, level: str = "INFO") -> None:
|
102
|
+
if verbose:
|
103
|
+
timestamp = datetime.now().strftime("%H:%M:%S.%f")[:-3] # Include milliseconds # noqa: DTZ005
|
104
|
+
typer.echo(f"[{timestamp}] {level}: {message}", file=sys.stderr)
|
105
|
+
|
106
|
+
def debug_print(message: str) -> None:
|
107
|
+
verbose_print(message, level="DEBUG")
|
108
|
+
|
109
|
+
start_time = time.time() if timing else None
|
110
|
+
|
111
|
+
# Use either positional input_value or --input-value option
|
112
|
+
final_input_value = input_value or input_value_option
|
113
|
+
|
114
|
+
# Validate input sources - exactly one must be provided
|
115
|
+
input_sources = [script_path is not None, flow_json is not None, bool(stdin)]
|
116
|
+
if sum(input_sources) != 1:
|
117
|
+
if sum(input_sources) == 0:
|
118
|
+
error_msg = "No input source provided. Must provide either script_path, --flow-json, or --stdin"
|
119
|
+
else:
|
120
|
+
error_msg = (
|
121
|
+
"Multiple input sources provided. Cannot use script_path, --flow-json, and "
|
122
|
+
"--stdin together. Choose exactly one."
|
123
|
+
)
|
124
|
+
output_error(error_msg, verbose=verbose)
|
125
|
+
raise typer.Exit(1)
|
126
|
+
|
127
|
+
temp_file_to_cleanup = None
|
128
|
+
|
129
|
+
if flow_json is not None:
|
130
|
+
verbose_print("Processing inline JSON content...")
|
131
|
+
try:
|
132
|
+
json_data = json.loads(flow_json)
|
133
|
+
verbose_print("JSON content is valid")
|
134
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as temp_file:
|
135
|
+
json.dump(json_data, temp_file, indent=2)
|
136
|
+
temp_file_to_cleanup = temp_file.name
|
137
|
+
script_path = Path(temp_file_to_cleanup)
|
138
|
+
verbose_print(f"Created temporary file: {script_path}")
|
139
|
+
except json.JSONDecodeError as e:
|
140
|
+
output_error(f"Invalid JSON content: {e}", verbose=verbose)
|
141
|
+
raise typer.Exit(1) from e
|
142
|
+
except Exception as e:
|
143
|
+
output_error(f"Error processing JSON content: {e}", verbose=verbose)
|
144
|
+
raise typer.Exit(1) from e
|
145
|
+
elif stdin:
|
146
|
+
verbose_print("Reading JSON content from stdin...")
|
147
|
+
try:
|
148
|
+
stdin_content = sys.stdin.read().strip()
|
149
|
+
if not stdin_content:
|
150
|
+
output_error("No content received from stdin", verbose=verbose)
|
151
|
+
raise typer.Exit(1)
|
152
|
+
json_data = json.loads(stdin_content)
|
153
|
+
verbose_print("JSON content from stdin is valid")
|
154
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".json", delete=False) as temp_file:
|
155
|
+
json.dump(json_data, temp_file, indent=2)
|
156
|
+
temp_file_to_cleanup = temp_file.name
|
157
|
+
script_path = Path(temp_file_to_cleanup)
|
158
|
+
verbose_print(f"Created temporary file from stdin: {script_path}")
|
159
|
+
except json.JSONDecodeError as e:
|
160
|
+
output_error(f"Invalid JSON content from stdin: {e}", verbose=verbose)
|
161
|
+
raise typer.Exit(1) from e
|
162
|
+
except Exception as e:
|
163
|
+
output_error(f"Error reading from stdin: {e}", verbose=verbose)
|
164
|
+
raise typer.Exit(1) from e
|
165
|
+
|
166
|
+
try:
|
167
|
+
if not script_path or not script_path.exists():
|
168
|
+
error_msg = f"File '{script_path}' does not exist."
|
169
|
+
raise ValueError(error_msg)
|
170
|
+
if not script_path.is_file():
|
171
|
+
error_msg = f"'{script_path}' is not a file."
|
172
|
+
raise ValueError(error_msg)
|
173
|
+
file_extension = script_path.suffix.lower()
|
174
|
+
if file_extension not in [".py", ".json"]:
|
175
|
+
error_msg = f"'{script_path}' must be a .py or .json file."
|
176
|
+
raise ValueError(error_msg)
|
177
|
+
file_type = "Python script" if file_extension == ".py" else "JSON flow"
|
178
|
+
verbose_print(f"Analyzing {file_type}: {script_path}")
|
179
|
+
if file_extension == ".py":
|
180
|
+
graph_info = find_graph_variable(script_path)
|
181
|
+
if not graph_info:
|
182
|
+
error_msg = (
|
183
|
+
"No 'graph' variable found in the script. Expected to find an assignment like: graph = Graph(...)"
|
184
|
+
)
|
185
|
+
raise ValueError(error_msg)
|
186
|
+
verbose_print(f"Found 'graph' variable at line {graph_info['line_number']}")
|
187
|
+
verbose_print(f"Type: {graph_info['type']}")
|
188
|
+
verbose_print(f"Source: {graph_info['source_line']}")
|
189
|
+
verbose_print("Loading and executing script...")
|
190
|
+
graph = load_graph_from_script(script_path)
|
191
|
+
elif file_extension == ".json":
|
192
|
+
verbose_print("Valid JSON flow file detected")
|
193
|
+
verbose_print("\nLoading and executing JSON flow...")
|
194
|
+
from lfx.load import aload_flow_from_json
|
195
|
+
|
196
|
+
graph = await aload_flow_from_json(script_path, disable_logs=not verbose)
|
197
|
+
except Exception as e:
|
198
|
+
error_type = type(e).__name__
|
199
|
+
verbose_print(f"Graph loading failed with {error_type}", level="ERROR")
|
200
|
+
|
201
|
+
if verbose:
|
202
|
+
# Enhanced error context for better debugging
|
203
|
+
debug_print(f"Exception type: {error_type}")
|
204
|
+
debug_print(f"Exception message: {e!s}")
|
205
|
+
|
206
|
+
# Try to identify common error patterns
|
207
|
+
if "ModuleNotFoundError" in str(e) or "No module named" in str(e):
|
208
|
+
verbose_print("This appears to be a missing dependency issue", level="WARN")
|
209
|
+
if "langchain" in str(e).lower():
|
210
|
+
verbose_print(
|
211
|
+
"Missing LangChain dependency detected. Try: pip install langchain-<provider>",
|
212
|
+
level="WARN",
|
213
|
+
)
|
214
|
+
elif "ImportError" in str(e):
|
215
|
+
verbose_print("This appears to be an import issue - check component dependencies", level="WARN")
|
216
|
+
elif "AttributeError" in str(e):
|
217
|
+
verbose_print("This appears to be a component configuration issue", level="WARN")
|
218
|
+
|
219
|
+
# Show full traceback in debug mode
|
220
|
+
logger.exception("Failed to load graph - full traceback:")
|
221
|
+
|
222
|
+
output_error(f"Failed to load graph: {e}", verbose=verbose)
|
223
|
+
if temp_file_to_cleanup:
|
224
|
+
try:
|
225
|
+
Path(temp_file_to_cleanup).unlink()
|
226
|
+
verbose_print(f"Cleaned up temporary file: {temp_file_to_cleanup}", level="SUCCESS")
|
227
|
+
except OSError:
|
228
|
+
pass
|
229
|
+
raise typer.Exit(1) from e
|
230
|
+
|
231
|
+
inputs = InputValueRequest(input_value=final_input_value) if final_input_value else None
|
232
|
+
|
233
|
+
# Mark end of loading phase if timing
|
234
|
+
load_end_time = time.time() if timing else None
|
235
|
+
|
236
|
+
verbose_print("Preparing graph for execution...")
|
237
|
+
try:
|
238
|
+
# Add detailed preparation steps
|
239
|
+
if verbose:
|
240
|
+
debug_print(f"Graph contains {len(graph.vertices)} vertices")
|
241
|
+
debug_print(f"Graph contains {len(graph.edges)} edges")
|
242
|
+
|
243
|
+
# Show component types being used
|
244
|
+
component_types = set()
|
245
|
+
for vertex in graph.vertices:
|
246
|
+
if hasattr(vertex, "display_name"):
|
247
|
+
component_types.add(vertex.display_name)
|
248
|
+
debug_print(f"Component types in graph: {', '.join(sorted(component_types))}")
|
249
|
+
|
250
|
+
graph.prepare()
|
251
|
+
verbose_print("Graph preparation completed", level="SUCCESS")
|
252
|
+
|
253
|
+
# Validate global variables for environment compatibility
|
254
|
+
if check_variables:
|
255
|
+
verbose_print("Validating global variables...")
|
256
|
+
validation_errors = validate_global_variables_for_env(graph)
|
257
|
+
if validation_errors:
|
258
|
+
error_details = "Global variable validation failed: " + "; ".join(validation_errors)
|
259
|
+
verbose_print(f"Variable validation failed: {len(validation_errors)} errors", level="ERROR")
|
260
|
+
for error in validation_errors:
|
261
|
+
debug_print(f"Validation error: {error}")
|
262
|
+
output_error(error_details, verbose=verbose)
|
263
|
+
if temp_file_to_cleanup:
|
264
|
+
try:
|
265
|
+
Path(temp_file_to_cleanup).unlink()
|
266
|
+
verbose_print(f"Cleaned up temporary file: {temp_file_to_cleanup}", level="SUCCESS")
|
267
|
+
except OSError:
|
268
|
+
pass
|
269
|
+
if validation_errors:
|
270
|
+
raise typer.Exit(1)
|
271
|
+
verbose_print("Global variable validation passed", level="SUCCESS")
|
272
|
+
else:
|
273
|
+
verbose_print("Global variable validation skipped", level="SUCCESS")
|
274
|
+
except Exception as e:
|
275
|
+
error_type = type(e).__name__
|
276
|
+
verbose_print(f"Graph preparation failed with {error_type}", level="ERROR")
|
277
|
+
|
278
|
+
if verbose:
|
279
|
+
debug_print(f"Preparation error: {e!s}")
|
280
|
+
logger.exception("Failed to prepare graph - full traceback:")
|
281
|
+
|
282
|
+
output_error(f"Failed to prepare graph: {e}", verbose=verbose)
|
283
|
+
if temp_file_to_cleanup:
|
284
|
+
try:
|
285
|
+
Path(temp_file_to_cleanup).unlink()
|
286
|
+
verbose_print(f"Cleaned up temporary file: {temp_file_to_cleanup}")
|
287
|
+
except OSError:
|
288
|
+
pass
|
289
|
+
raise typer.Exit(1) from e
|
290
|
+
|
291
|
+
verbose_print("Executing graph...")
|
292
|
+
execution_start_time = time.time() if timing else None
|
293
|
+
|
294
|
+
if verbose:
|
295
|
+
debug_print("Setting up execution environment")
|
296
|
+
if inputs:
|
297
|
+
debug_print(f"Input provided: {inputs.input_value}")
|
298
|
+
else:
|
299
|
+
debug_print("No input provided")
|
300
|
+
|
301
|
+
captured_stdout = StringIO()
|
302
|
+
captured_stderr = StringIO()
|
303
|
+
original_stdout = sys.stdout
|
304
|
+
original_stderr = sys.stderr
|
305
|
+
|
306
|
+
# Track component timing if requested
|
307
|
+
component_timings = [] if timing else None
|
308
|
+
execution_step_start = execution_start_time if timing else None
|
309
|
+
|
310
|
+
try:
|
311
|
+
sys.stdout = captured_stdout
|
312
|
+
sys.stderr = captured_stderr
|
313
|
+
results = []
|
314
|
+
|
315
|
+
verbose_print("Starting graph execution...", level="DEBUG")
|
316
|
+
result_count = 0
|
317
|
+
|
318
|
+
async for result in graph.async_start(inputs):
|
319
|
+
result_count += 1
|
320
|
+
if verbose:
|
321
|
+
debug_print(f"Processing result #{result_count}")
|
322
|
+
if hasattr(result, "vertex") and hasattr(result.vertex, "display_name"):
|
323
|
+
debug_print(f"Component: {result.vertex.display_name}")
|
324
|
+
if timing:
|
325
|
+
step_end_time = time.time()
|
326
|
+
step_duration = step_end_time - execution_step_start
|
327
|
+
|
328
|
+
# Extract component information
|
329
|
+
if hasattr(result, "vertex"):
|
330
|
+
component_name = getattr(result.vertex, "display_name", "Unknown")
|
331
|
+
component_id = getattr(result.vertex, "id", "Unknown")
|
332
|
+
component_timings.append(
|
333
|
+
{
|
334
|
+
"component": component_name,
|
335
|
+
"component_id": component_id,
|
336
|
+
"duration": step_duration,
|
337
|
+
"cumulative_time": step_end_time - execution_start_time,
|
338
|
+
}
|
339
|
+
)
|
340
|
+
|
341
|
+
execution_step_start = step_end_time
|
342
|
+
|
343
|
+
results.append(result)
|
344
|
+
|
345
|
+
verbose_print(f"Graph execution completed. Processed {result_count} results", level="SUCCESS")
|
346
|
+
|
347
|
+
except Exception as e:
|
348
|
+
sys.stdout = original_stdout
|
349
|
+
sys.stderr = original_stderr
|
350
|
+
|
351
|
+
error_type = type(e).__name__
|
352
|
+
verbose_print(f"Graph execution failed with {error_type}", level="ERROR")
|
353
|
+
|
354
|
+
if verbose:
|
355
|
+
debug_print(f"Execution error: {e!s}")
|
356
|
+
debug_print(f"Failed after processing {result_count} results")
|
357
|
+
|
358
|
+
# Capture any output that was generated before the error
|
359
|
+
captured_content = captured_stdout.getvalue() + captured_stderr.getvalue()
|
360
|
+
if captured_content.strip():
|
361
|
+
debug_print("Captured output before error:")
|
362
|
+
for line in captured_content.strip().split("\n"):
|
363
|
+
debug_print(f" | {line}")
|
364
|
+
|
365
|
+
# Provide context about common execution errors
|
366
|
+
if "list can't be used in 'await' expression" in str(e):
|
367
|
+
verbose_print("This appears to be an async/await mismatch in a component", level="WARN")
|
368
|
+
verbose_print("Check that async methods are properly awaited", level="WARN")
|
369
|
+
elif "AttributeError" in error_type and "NoneType" in str(e):
|
370
|
+
verbose_print("This appears to be a null reference error", level="WARN")
|
371
|
+
verbose_print("A component may be receiving unexpected None values", level="WARN")
|
372
|
+
elif "ConnectionError" in str(e) or "TimeoutError" in str(e):
|
373
|
+
verbose_print("This appears to be a network connectivity issue", level="WARN")
|
374
|
+
verbose_print("Check API keys and network connectivity", level="WARN")
|
375
|
+
|
376
|
+
logger.exception("Failed to execute graph - full traceback:")
|
377
|
+
|
378
|
+
output_error(f"Failed to execute graph: {e}", verbose=verbose)
|
379
|
+
if temp_file_to_cleanup:
|
380
|
+
try:
|
381
|
+
Path(temp_file_to_cleanup).unlink()
|
382
|
+
verbose_print(f"Cleaned up temporary file: {temp_file_to_cleanup}", level="SUCCESS")
|
383
|
+
except OSError:
|
384
|
+
pass
|
385
|
+
raise typer.Exit(1) from e
|
386
|
+
finally:
|
387
|
+
sys.stdout = original_stdout
|
388
|
+
sys.stderr = original_stderr
|
389
|
+
if temp_file_to_cleanup:
|
390
|
+
try:
|
391
|
+
Path(temp_file_to_cleanup).unlink()
|
392
|
+
verbose_print(f"Cleaned up temporary file: {temp_file_to_cleanup}")
|
393
|
+
except OSError:
|
394
|
+
pass
|
395
|
+
|
396
|
+
execution_end_time = time.time() if timing else None
|
397
|
+
|
398
|
+
captured_logs = captured_stdout.getvalue() + captured_stderr.getvalue()
|
399
|
+
|
400
|
+
# Create timing metadata if requested
|
401
|
+
timing_metadata = None
|
402
|
+
if timing:
|
403
|
+
load_duration = load_end_time - start_time
|
404
|
+
execution_duration = execution_end_time - execution_start_time
|
405
|
+
total_duration = execution_end_time - start_time
|
406
|
+
|
407
|
+
timing_metadata = {
|
408
|
+
"load_time": round(load_duration, 3),
|
409
|
+
"execution_time": round(execution_duration, 3),
|
410
|
+
"total_time": round(total_duration, 3),
|
411
|
+
"component_timings": [
|
412
|
+
{
|
413
|
+
"component": ct["component"],
|
414
|
+
"component_id": ct["component_id"],
|
415
|
+
"duration": round(ct["duration"], 3),
|
416
|
+
"cumulative_time": round(ct["cumulative_time"], 3),
|
417
|
+
}
|
418
|
+
for ct in component_timings
|
419
|
+
],
|
420
|
+
}
|
421
|
+
|
422
|
+
if output_format == "json":
|
423
|
+
result_data = extract_structured_result(results)
|
424
|
+
result_data["logs"] = captured_logs
|
425
|
+
if timing_metadata:
|
426
|
+
result_data["timing"] = timing_metadata
|
427
|
+
indent = 2 if verbose else None
|
428
|
+
typer.echo(json.dumps(result_data, indent=indent))
|
429
|
+
elif output_format in {"text", "message"}:
|
430
|
+
result_data = extract_structured_result(results)
|
431
|
+
output_text = result_data.get("result", result_data.get("text", ""))
|
432
|
+
typer.echo(str(output_text))
|
433
|
+
elif output_format == "result":
|
434
|
+
typer.echo(extract_text_from_result(results))
|
435
|
+
else:
|
436
|
+
result_data = extract_structured_result(results)
|
437
|
+
result_data["logs"] = captured_logs
|
438
|
+
if timing_metadata:
|
439
|
+
result_data["timing"] = timing_metadata
|
440
|
+
indent = 2 if verbose else None
|
441
|
+
typer.echo(json.dumps(result_data, indent=indent))
|
lfx/cli/script_loader.py
ADDED
@@ -0,0 +1,247 @@
|
|
1
|
+
"""Script loading utilities for LFX CLI.
|
2
|
+
|
3
|
+
This module provides functionality to load and validate Python scripts
|
4
|
+
containing LFX graph variables.
|
5
|
+
"""
|
6
|
+
|
7
|
+
import ast
|
8
|
+
import importlib.util
|
9
|
+
import json
|
10
|
+
import sys
|
11
|
+
from contextlib import contextmanager
|
12
|
+
from pathlib import Path
|
13
|
+
from typing import TYPE_CHECKING, Any
|
14
|
+
|
15
|
+
import typer
|
16
|
+
|
17
|
+
from lfx.graph import Graph
|
18
|
+
|
19
|
+
if TYPE_CHECKING:
|
20
|
+
from lfx.schema.message import Message
|
21
|
+
|
22
|
+
|
23
|
+
@contextmanager
|
24
|
+
def temporary_sys_path(path: str):
|
25
|
+
"""Temporarily add a path to sys.path."""
|
26
|
+
if path not in sys.path:
|
27
|
+
sys.path.insert(0, path)
|
28
|
+
try:
|
29
|
+
yield
|
30
|
+
finally:
|
31
|
+
sys.path.remove(path)
|
32
|
+
else:
|
33
|
+
yield
|
34
|
+
|
35
|
+
|
36
|
+
def _load_module_from_script(script_path: Path) -> Any:
|
37
|
+
"""Load a Python module from a script file."""
|
38
|
+
spec = importlib.util.spec_from_file_location("script_module", script_path)
|
39
|
+
if spec is None or spec.loader is None:
|
40
|
+
msg = f"Could not create module spec for '{script_path}'"
|
41
|
+
raise ImportError(msg)
|
42
|
+
|
43
|
+
module = importlib.util.module_from_spec(spec)
|
44
|
+
|
45
|
+
with temporary_sys_path(str(script_path.parent)):
|
46
|
+
spec.loader.exec_module(module)
|
47
|
+
|
48
|
+
return module
|
49
|
+
|
50
|
+
|
51
|
+
def _validate_graph_instance(graph_obj: Any) -> Graph:
|
52
|
+
"""Extract information from a graph object."""
|
53
|
+
if not isinstance(graph_obj, Graph):
|
54
|
+
msg = f"Graph object is not a LFX Graph instance: {type(graph_obj)}"
|
55
|
+
raise TypeError(msg)
|
56
|
+
|
57
|
+
# Find ChatInput and ChatOutput components
|
58
|
+
display_names: set[str] = set()
|
59
|
+
for vertex in graph_obj.vertices:
|
60
|
+
if vertex.custom_component is not None:
|
61
|
+
display_names.add(vertex.custom_component.display_name)
|
62
|
+
|
63
|
+
if "Chat Input" not in display_names:
|
64
|
+
msg = f"Graph does not contain any ChatInput component. Vertices: {display_names}"
|
65
|
+
raise ValueError(msg)
|
66
|
+
|
67
|
+
if "Chat Output" not in display_names:
|
68
|
+
msg = f"Graph does not contain any ChatOutput component. Vertices: {display_names}"
|
69
|
+
raise ValueError(msg)
|
70
|
+
|
71
|
+
return graph_obj
|
72
|
+
|
73
|
+
|
74
|
+
def load_graph_from_script(script_path: Path) -> Graph:
|
75
|
+
"""Load and execute a Python script to extract the 'graph' variable.
|
76
|
+
|
77
|
+
Args:
|
78
|
+
script_path (Path): Path to the Python script file
|
79
|
+
|
80
|
+
Returns:
|
81
|
+
dict: Information about the loaded graph variable including the graph object itself
|
82
|
+
"""
|
83
|
+
try:
|
84
|
+
# Load the module
|
85
|
+
module = _load_module_from_script(script_path)
|
86
|
+
|
87
|
+
# Check if 'graph' variable exists
|
88
|
+
if not hasattr(module, "graph"):
|
89
|
+
msg = "No 'graph' variable found in the executed script"
|
90
|
+
raise ValueError(msg)
|
91
|
+
|
92
|
+
# Extract graph information
|
93
|
+
graph_obj = module.graph
|
94
|
+
return _validate_graph_instance(graph_obj)
|
95
|
+
|
96
|
+
except (
|
97
|
+
ImportError,
|
98
|
+
AttributeError,
|
99
|
+
ModuleNotFoundError,
|
100
|
+
SyntaxError,
|
101
|
+
TypeError,
|
102
|
+
ValueError,
|
103
|
+
FileNotFoundError,
|
104
|
+
) as e:
|
105
|
+
error_msg = f"Error executing script '{script_path}': {e}"
|
106
|
+
raise RuntimeError(error_msg) from e
|
107
|
+
|
108
|
+
|
109
|
+
def extract_message_from_result(results: list) -> str:
|
110
|
+
"""Extract the message from the results."""
|
111
|
+
for result in results:
|
112
|
+
if (
|
113
|
+
hasattr(result, "vertex")
|
114
|
+
and result.vertex.custom_component
|
115
|
+
and result.vertex.custom_component.display_name == "Chat Output"
|
116
|
+
):
|
117
|
+
message: Message = result.result_dict.results["message"]
|
118
|
+
try:
|
119
|
+
# Parse the JSON to get just the text content
|
120
|
+
return json.dumps(json.loads(message.model_dump_json()), ensure_ascii=False)
|
121
|
+
except (json.JSONDecodeError, AttributeError):
|
122
|
+
# Fallback to string representation
|
123
|
+
return str(message)
|
124
|
+
return "No response generated"
|
125
|
+
|
126
|
+
|
127
|
+
def extract_text_from_result(results: list) -> str:
|
128
|
+
"""Extract just the text content from the results."""
|
129
|
+
for result in results:
|
130
|
+
if (
|
131
|
+
hasattr(result, "vertex")
|
132
|
+
and result.vertex.custom_component
|
133
|
+
and result.vertex.custom_component.display_name == "Chat Output"
|
134
|
+
):
|
135
|
+
message: dict | Message = result.result_dict.results.get("message")
|
136
|
+
try:
|
137
|
+
# Return just the text content
|
138
|
+
if isinstance(message, dict):
|
139
|
+
text_content = message.get("text") if message.get("text") else str(message)
|
140
|
+
else:
|
141
|
+
text_content = message.text
|
142
|
+
return str(text_content)
|
143
|
+
except AttributeError:
|
144
|
+
# Fallback to string representation
|
145
|
+
return str(message)
|
146
|
+
return "No response generated"
|
147
|
+
|
148
|
+
|
149
|
+
def extract_structured_result(results: list, *, extract_text: bool = True) -> dict:
|
150
|
+
"""Extract structured result data from the results."""
|
151
|
+
for result in results:
|
152
|
+
if (
|
153
|
+
hasattr(result, "vertex")
|
154
|
+
and result.vertex.custom_component
|
155
|
+
and result.vertex.custom_component.display_name == "Chat Output"
|
156
|
+
):
|
157
|
+
message: Message = result.result_dict.results["message"]
|
158
|
+
try:
|
159
|
+
result_message = message.text if extract_text and hasattr(message, "text") else message
|
160
|
+
except (AttributeError, TypeError, ValueError) as e:
|
161
|
+
return {
|
162
|
+
"text": str(message),
|
163
|
+
"type": "message",
|
164
|
+
"component": result.vertex.custom_component.display_name,
|
165
|
+
"component_id": result.vertex.id,
|
166
|
+
"success": True,
|
167
|
+
"warning": f"Could not extract text properly: {e}",
|
168
|
+
}
|
169
|
+
|
170
|
+
return {
|
171
|
+
"result": result_message,
|
172
|
+
"type": "message",
|
173
|
+
"component": result.vertex.custom_component.display_name,
|
174
|
+
"component_id": result.vertex.id,
|
175
|
+
"success": True,
|
176
|
+
}
|
177
|
+
return {"text": "No response generated", "type": "error", "success": False}
|
178
|
+
|
179
|
+
|
180
|
+
def find_graph_variable(script_path: Path) -> dict | None:
|
181
|
+
"""Parse a Python script and find the 'graph' variable assignment.
|
182
|
+
|
183
|
+
Args:
|
184
|
+
script_path (Path): Path to the Python script file
|
185
|
+
|
186
|
+
Returns:
|
187
|
+
dict | None: Information about the graph variable if found, None otherwise
|
188
|
+
"""
|
189
|
+
try:
|
190
|
+
with script_path.open(encoding="utf-8") as f:
|
191
|
+
content = f.read()
|
192
|
+
|
193
|
+
# Parse the script using AST
|
194
|
+
tree = ast.parse(content)
|
195
|
+
|
196
|
+
# Look for assignments to 'graph' variable
|
197
|
+
for node in ast.walk(tree):
|
198
|
+
if isinstance(node, ast.Assign):
|
199
|
+
# Check if any target is named 'graph'
|
200
|
+
for target in node.targets:
|
201
|
+
if isinstance(target, ast.Name) and target.id == "graph":
|
202
|
+
# Found a graph assignment
|
203
|
+
line_number = node.lineno
|
204
|
+
|
205
|
+
# Try to extract some information about the assignment
|
206
|
+
if isinstance(node.value, ast.Call):
|
207
|
+
# It's a function call like Graph(...)
|
208
|
+
if isinstance(node.value.func, ast.Name):
|
209
|
+
func_name = node.value.func.id
|
210
|
+
elif isinstance(node.value.func, ast.Attribute):
|
211
|
+
# Handle cases like Graph.from_payload(...)
|
212
|
+
if isinstance(node.value.func.value, ast.Name):
|
213
|
+
func_name = f"{node.value.func.value.id}.{node.value.func.attr}"
|
214
|
+
else:
|
215
|
+
func_name = node.value.func.attr
|
216
|
+
else:
|
217
|
+
func_name = "Unknown"
|
218
|
+
|
219
|
+
# Count arguments
|
220
|
+
arg_count = len(node.value.args) + len(node.value.keywords)
|
221
|
+
|
222
|
+
return {
|
223
|
+
"line_number": line_number,
|
224
|
+
"type": "function_call",
|
225
|
+
"function": func_name,
|
226
|
+
"arg_count": arg_count,
|
227
|
+
"source_line": content.split("\n")[line_number - 1].strip(),
|
228
|
+
}
|
229
|
+
# Some other type of assignment
|
230
|
+
return {
|
231
|
+
"line_number": line_number,
|
232
|
+
"type": "assignment",
|
233
|
+
"source_line": content.split("\n")[line_number - 1].strip(),
|
234
|
+
}
|
235
|
+
|
236
|
+
except FileNotFoundError:
|
237
|
+
typer.echo(f"Error: File '{script_path}' not found.")
|
238
|
+
return None
|
239
|
+
except SyntaxError as e:
|
240
|
+
typer.echo(f"Error: Invalid Python syntax in '{script_path}': {e}")
|
241
|
+
return None
|
242
|
+
except (OSError, UnicodeDecodeError) as e:
|
243
|
+
typer.echo(f"Error parsing '{script_path}': {e}")
|
244
|
+
return None
|
245
|
+
else:
|
246
|
+
# No graph variable found
|
247
|
+
return None
|