lfx-nightly 0.2.0.dev25__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of lfx-nightly might be problematic. Click here for more details.
- lfx/__init__.py +0 -0
- lfx/__main__.py +25 -0
- lfx/_assets/component_index.json +1 -0
- lfx/base/__init__.py +0 -0
- lfx/base/agents/__init__.py +0 -0
- lfx/base/agents/agent.py +375 -0
- lfx/base/agents/altk_base_agent.py +380 -0
- lfx/base/agents/altk_tool_wrappers.py +565 -0
- lfx/base/agents/callback.py +130 -0
- lfx/base/agents/context.py +109 -0
- lfx/base/agents/crewai/__init__.py +0 -0
- lfx/base/agents/crewai/crew.py +231 -0
- lfx/base/agents/crewai/tasks.py +12 -0
- lfx/base/agents/default_prompts.py +23 -0
- lfx/base/agents/errors.py +15 -0
- lfx/base/agents/events.py +430 -0
- lfx/base/agents/utils.py +237 -0
- lfx/base/astra_assistants/__init__.py +0 -0
- lfx/base/astra_assistants/util.py +171 -0
- lfx/base/chains/__init__.py +0 -0
- lfx/base/chains/model.py +19 -0
- lfx/base/composio/__init__.py +0 -0
- lfx/base/composio/composio_base.py +2584 -0
- lfx/base/compressors/__init__.py +0 -0
- lfx/base/compressors/model.py +60 -0
- lfx/base/constants.py +46 -0
- lfx/base/curl/__init__.py +0 -0
- lfx/base/curl/parse.py +188 -0
- lfx/base/data/__init__.py +5 -0
- lfx/base/data/base_file.py +810 -0
- lfx/base/data/docling_utils.py +338 -0
- lfx/base/data/storage_utils.py +192 -0
- lfx/base/data/utils.py +362 -0
- lfx/base/datastax/__init__.py +5 -0
- lfx/base/datastax/astradb_base.py +896 -0
- lfx/base/document_transformers/__init__.py +0 -0
- lfx/base/document_transformers/model.py +43 -0
- lfx/base/embeddings/__init__.py +0 -0
- lfx/base/embeddings/aiml_embeddings.py +62 -0
- lfx/base/embeddings/embeddings_class.py +113 -0
- lfx/base/embeddings/model.py +26 -0
- lfx/base/flow_processing/__init__.py +0 -0
- lfx/base/flow_processing/utils.py +86 -0
- lfx/base/huggingface/__init__.py +0 -0
- lfx/base/huggingface/model_bridge.py +133 -0
- lfx/base/io/__init__.py +0 -0
- lfx/base/io/chat.py +21 -0
- lfx/base/io/text.py +22 -0
- lfx/base/knowledge_bases/__init__.py +3 -0
- lfx/base/knowledge_bases/knowledge_base_utils.py +137 -0
- lfx/base/langchain_utilities/__init__.py +0 -0
- lfx/base/langchain_utilities/model.py +35 -0
- lfx/base/langchain_utilities/spider_constants.py +1 -0
- lfx/base/langwatch/__init__.py +0 -0
- lfx/base/langwatch/utils.py +18 -0
- lfx/base/mcp/__init__.py +0 -0
- lfx/base/mcp/constants.py +2 -0
- lfx/base/mcp/util.py +1659 -0
- lfx/base/memory/__init__.py +0 -0
- lfx/base/memory/memory.py +49 -0
- lfx/base/memory/model.py +38 -0
- lfx/base/models/__init__.py +3 -0
- lfx/base/models/aiml_constants.py +51 -0
- lfx/base/models/anthropic_constants.py +51 -0
- lfx/base/models/aws_constants.py +151 -0
- lfx/base/models/chat_result.py +76 -0
- lfx/base/models/cometapi_constants.py +54 -0
- lfx/base/models/google_generative_ai_constants.py +70 -0
- lfx/base/models/google_generative_ai_model.py +38 -0
- lfx/base/models/groq_constants.py +150 -0
- lfx/base/models/groq_model_discovery.py +265 -0
- lfx/base/models/model.py +375 -0
- lfx/base/models/model_input_constants.py +378 -0
- lfx/base/models/model_metadata.py +41 -0
- lfx/base/models/model_utils.py +108 -0
- lfx/base/models/novita_constants.py +35 -0
- lfx/base/models/ollama_constants.py +52 -0
- lfx/base/models/openai_constants.py +129 -0
- lfx/base/models/sambanova_constants.py +18 -0
- lfx/base/models/watsonx_constants.py +36 -0
- lfx/base/processing/__init__.py +0 -0
- lfx/base/prompts/__init__.py +0 -0
- lfx/base/prompts/api_utils.py +224 -0
- lfx/base/prompts/utils.py +61 -0
- lfx/base/textsplitters/__init__.py +0 -0
- lfx/base/textsplitters/model.py +28 -0
- lfx/base/tools/__init__.py +0 -0
- lfx/base/tools/base.py +26 -0
- lfx/base/tools/component_tool.py +325 -0
- lfx/base/tools/constants.py +49 -0
- lfx/base/tools/flow_tool.py +132 -0
- lfx/base/tools/run_flow.py +698 -0
- lfx/base/vectorstores/__init__.py +0 -0
- lfx/base/vectorstores/model.py +193 -0
- lfx/base/vectorstores/utils.py +22 -0
- lfx/base/vectorstores/vector_store_connection_decorator.py +52 -0
- lfx/cli/__init__.py +5 -0
- lfx/cli/commands.py +327 -0
- lfx/cli/common.py +650 -0
- lfx/cli/run.py +506 -0
- lfx/cli/script_loader.py +289 -0
- lfx/cli/serve_app.py +546 -0
- lfx/cli/validation.py +69 -0
- lfx/components/FAISS/__init__.py +34 -0
- lfx/components/FAISS/faiss.py +111 -0
- lfx/components/Notion/__init__.py +19 -0
- lfx/components/Notion/add_content_to_page.py +269 -0
- lfx/components/Notion/create_page.py +94 -0
- lfx/components/Notion/list_database_properties.py +68 -0
- lfx/components/Notion/list_pages.py +122 -0
- lfx/components/Notion/list_users.py +77 -0
- lfx/components/Notion/page_content_viewer.py +93 -0
- lfx/components/Notion/search.py +111 -0
- lfx/components/Notion/update_page_property.py +114 -0
- lfx/components/__init__.py +428 -0
- lfx/components/_importing.py +42 -0
- lfx/components/agentql/__init__.py +3 -0
- lfx/components/agentql/agentql_api.py +151 -0
- lfx/components/aiml/__init__.py +37 -0
- lfx/components/aiml/aiml.py +115 -0
- lfx/components/aiml/aiml_embeddings.py +37 -0
- lfx/components/altk/__init__.py +34 -0
- lfx/components/altk/altk_agent.py +193 -0
- lfx/components/amazon/__init__.py +36 -0
- lfx/components/amazon/amazon_bedrock_converse.py +195 -0
- lfx/components/amazon/amazon_bedrock_embedding.py +109 -0
- lfx/components/amazon/amazon_bedrock_model.py +130 -0
- lfx/components/amazon/s3_bucket_uploader.py +211 -0
- lfx/components/anthropic/__init__.py +34 -0
- lfx/components/anthropic/anthropic.py +187 -0
- lfx/components/apify/__init__.py +5 -0
- lfx/components/apify/apify_actor.py +325 -0
- lfx/components/arxiv/__init__.py +3 -0
- lfx/components/arxiv/arxiv.py +169 -0
- lfx/components/assemblyai/__init__.py +46 -0
- lfx/components/assemblyai/assemblyai_get_subtitles.py +83 -0
- lfx/components/assemblyai/assemblyai_lemur.py +183 -0
- lfx/components/assemblyai/assemblyai_list_transcripts.py +95 -0
- lfx/components/assemblyai/assemblyai_poll_transcript.py +72 -0
- lfx/components/assemblyai/assemblyai_start_transcript.py +188 -0
- lfx/components/azure/__init__.py +37 -0
- lfx/components/azure/azure_openai.py +95 -0
- lfx/components/azure/azure_openai_embeddings.py +83 -0
- lfx/components/baidu/__init__.py +32 -0
- lfx/components/baidu/baidu_qianfan_chat.py +113 -0
- lfx/components/bing/__init__.py +3 -0
- lfx/components/bing/bing_search_api.py +61 -0
- lfx/components/cassandra/__init__.py +40 -0
- lfx/components/cassandra/cassandra.py +264 -0
- lfx/components/cassandra/cassandra_chat.py +92 -0
- lfx/components/cassandra/cassandra_graph.py +238 -0
- lfx/components/chains/__init__.py +3 -0
- lfx/components/chroma/__init__.py +34 -0
- lfx/components/chroma/chroma.py +169 -0
- lfx/components/cleanlab/__init__.py +40 -0
- lfx/components/cleanlab/cleanlab_evaluator.py +155 -0
- lfx/components/cleanlab/cleanlab_rag_evaluator.py +254 -0
- lfx/components/cleanlab/cleanlab_remediator.py +131 -0
- lfx/components/clickhouse/__init__.py +34 -0
- lfx/components/clickhouse/clickhouse.py +135 -0
- lfx/components/cloudflare/__init__.py +32 -0
- lfx/components/cloudflare/cloudflare.py +81 -0
- lfx/components/cohere/__init__.py +40 -0
- lfx/components/cohere/cohere_embeddings.py +81 -0
- lfx/components/cohere/cohere_models.py +46 -0
- lfx/components/cohere/cohere_rerank.py +51 -0
- lfx/components/cometapi/__init__.py +32 -0
- lfx/components/cometapi/cometapi.py +166 -0
- lfx/components/composio/__init__.py +222 -0
- lfx/components/composio/agentql_composio.py +11 -0
- lfx/components/composio/agiled_composio.py +11 -0
- lfx/components/composio/airtable_composio.py +11 -0
- lfx/components/composio/apollo_composio.py +11 -0
- lfx/components/composio/asana_composio.py +11 -0
- lfx/components/composio/attio_composio.py +11 -0
- lfx/components/composio/bitbucket_composio.py +11 -0
- lfx/components/composio/bolna_composio.py +11 -0
- lfx/components/composio/brightdata_composio.py +11 -0
- lfx/components/composio/calendly_composio.py +11 -0
- lfx/components/composio/canva_composio.py +11 -0
- lfx/components/composio/canvas_composio.py +11 -0
- lfx/components/composio/coda_composio.py +11 -0
- lfx/components/composio/composio_api.py +278 -0
- lfx/components/composio/contentful_composio.py +11 -0
- lfx/components/composio/digicert_composio.py +11 -0
- lfx/components/composio/discord_composio.py +11 -0
- lfx/components/composio/dropbox_compnent.py +11 -0
- lfx/components/composio/elevenlabs_composio.py +11 -0
- lfx/components/composio/exa_composio.py +11 -0
- lfx/components/composio/figma_composio.py +11 -0
- lfx/components/composio/finage_composio.py +11 -0
- lfx/components/composio/firecrawl_composio.py +11 -0
- lfx/components/composio/fireflies_composio.py +11 -0
- lfx/components/composio/fixer_composio.py +11 -0
- lfx/components/composio/flexisign_composio.py +11 -0
- lfx/components/composio/freshdesk_composio.py +11 -0
- lfx/components/composio/github_composio.py +11 -0
- lfx/components/composio/gmail_composio.py +38 -0
- lfx/components/composio/googlebigquery_composio.py +11 -0
- lfx/components/composio/googlecalendar_composio.py +11 -0
- lfx/components/composio/googleclassroom_composio.py +11 -0
- lfx/components/composio/googledocs_composio.py +11 -0
- lfx/components/composio/googlemeet_composio.py +11 -0
- lfx/components/composio/googlesheets_composio.py +11 -0
- lfx/components/composio/googletasks_composio.py +8 -0
- lfx/components/composio/heygen_composio.py +11 -0
- lfx/components/composio/instagram_composio.py +11 -0
- lfx/components/composio/jira_composio.py +11 -0
- lfx/components/composio/jotform_composio.py +11 -0
- lfx/components/composio/klaviyo_composio.py +11 -0
- lfx/components/composio/linear_composio.py +11 -0
- lfx/components/composio/listennotes_composio.py +11 -0
- lfx/components/composio/mem0_composio.py +11 -0
- lfx/components/composio/miro_composio.py +11 -0
- lfx/components/composio/missive_composio.py +11 -0
- lfx/components/composio/notion_composio.py +11 -0
- lfx/components/composio/onedrive_composio.py +11 -0
- lfx/components/composio/outlook_composio.py +11 -0
- lfx/components/composio/pandadoc_composio.py +11 -0
- lfx/components/composio/peopledatalabs_composio.py +11 -0
- lfx/components/composio/perplexityai_composio.py +11 -0
- lfx/components/composio/reddit_composio.py +11 -0
- lfx/components/composio/serpapi_composio.py +11 -0
- lfx/components/composio/slack_composio.py +11 -0
- lfx/components/composio/slackbot_composio.py +11 -0
- lfx/components/composio/snowflake_composio.py +11 -0
- lfx/components/composio/supabase_composio.py +11 -0
- lfx/components/composio/tavily_composio.py +11 -0
- lfx/components/composio/timelinesai_composio.py +11 -0
- lfx/components/composio/todoist_composio.py +11 -0
- lfx/components/composio/wrike_composio.py +11 -0
- lfx/components/composio/youtube_composio.py +11 -0
- lfx/components/confluence/__init__.py +3 -0
- lfx/components/confluence/confluence.py +84 -0
- lfx/components/couchbase/__init__.py +34 -0
- lfx/components/couchbase/couchbase.py +102 -0
- lfx/components/crewai/__init__.py +49 -0
- lfx/components/crewai/crewai.py +108 -0
- lfx/components/crewai/hierarchical_crew.py +47 -0
- lfx/components/crewai/hierarchical_task.py +45 -0
- lfx/components/crewai/sequential_crew.py +53 -0
- lfx/components/crewai/sequential_task.py +74 -0
- lfx/components/crewai/sequential_task_agent.py +144 -0
- lfx/components/cuga/__init__.py +34 -0
- lfx/components/cuga/cuga_agent.py +730 -0
- lfx/components/custom_component/__init__.py +34 -0
- lfx/components/custom_component/custom_component.py +31 -0
- lfx/components/data/__init__.py +114 -0
- lfx/components/data_source/__init__.py +58 -0
- lfx/components/data_source/api_request.py +577 -0
- lfx/components/data_source/csv_to_data.py +101 -0
- lfx/components/data_source/json_to_data.py +106 -0
- lfx/components/data_source/mock_data.py +398 -0
- lfx/components/data_source/news_search.py +166 -0
- lfx/components/data_source/rss.py +71 -0
- lfx/components/data_source/sql_executor.py +101 -0
- lfx/components/data_source/url.py +311 -0
- lfx/components/data_source/web_search.py +326 -0
- lfx/components/datastax/__init__.py +76 -0
- lfx/components/datastax/astradb_assistant_manager.py +307 -0
- lfx/components/datastax/astradb_chatmemory.py +40 -0
- lfx/components/datastax/astradb_cql.py +288 -0
- lfx/components/datastax/astradb_graph.py +217 -0
- lfx/components/datastax/astradb_tool.py +378 -0
- lfx/components/datastax/astradb_vectorize.py +122 -0
- lfx/components/datastax/astradb_vectorstore.py +449 -0
- lfx/components/datastax/create_assistant.py +59 -0
- lfx/components/datastax/create_thread.py +33 -0
- lfx/components/datastax/dotenv.py +36 -0
- lfx/components/datastax/get_assistant.py +38 -0
- lfx/components/datastax/getenvvar.py +31 -0
- lfx/components/datastax/graph_rag.py +141 -0
- lfx/components/datastax/hcd.py +315 -0
- lfx/components/datastax/list_assistants.py +26 -0
- lfx/components/datastax/run.py +90 -0
- lfx/components/deactivated/__init__.py +15 -0
- lfx/components/deactivated/amazon_kendra.py +66 -0
- lfx/components/deactivated/chat_litellm_model.py +158 -0
- lfx/components/deactivated/code_block_extractor.py +26 -0
- lfx/components/deactivated/documents_to_data.py +22 -0
- lfx/components/deactivated/embed.py +16 -0
- lfx/components/deactivated/extract_key_from_data.py +46 -0
- lfx/components/deactivated/json_document_builder.py +57 -0
- lfx/components/deactivated/list_flows.py +20 -0
- lfx/components/deactivated/mcp_sse.py +61 -0
- lfx/components/deactivated/mcp_stdio.py +62 -0
- lfx/components/deactivated/merge_data.py +93 -0
- lfx/components/deactivated/message.py +37 -0
- lfx/components/deactivated/metal.py +54 -0
- lfx/components/deactivated/multi_query.py +59 -0
- lfx/components/deactivated/retriever.py +43 -0
- lfx/components/deactivated/selective_passthrough.py +77 -0
- lfx/components/deactivated/should_run_next.py +40 -0
- lfx/components/deactivated/split_text.py +63 -0
- lfx/components/deactivated/store_message.py +24 -0
- lfx/components/deactivated/sub_flow.py +124 -0
- lfx/components/deactivated/vectara_self_query.py +76 -0
- lfx/components/deactivated/vector_store.py +24 -0
- lfx/components/deepseek/__init__.py +34 -0
- lfx/components/deepseek/deepseek.py +136 -0
- lfx/components/docling/__init__.py +43 -0
- lfx/components/docling/chunk_docling_document.py +186 -0
- lfx/components/docling/docling_inline.py +238 -0
- lfx/components/docling/docling_remote.py +195 -0
- lfx/components/docling/export_docling_document.py +117 -0
- lfx/components/documentloaders/__init__.py +3 -0
- lfx/components/duckduckgo/__init__.py +3 -0
- lfx/components/duckduckgo/duck_duck_go_search_run.py +92 -0
- lfx/components/elastic/__init__.py +37 -0
- lfx/components/elastic/elasticsearch.py +267 -0
- lfx/components/elastic/opensearch.py +789 -0
- lfx/components/elastic/opensearch_multimodal.py +1575 -0
- lfx/components/embeddings/__init__.py +37 -0
- lfx/components/embeddings/similarity.py +77 -0
- lfx/components/embeddings/text_embedder.py +65 -0
- lfx/components/exa/__init__.py +3 -0
- lfx/components/exa/exa_search.py +68 -0
- lfx/components/files_and_knowledge/__init__.py +47 -0
- lfx/components/files_and_knowledge/directory.py +113 -0
- lfx/components/files_and_knowledge/file.py +841 -0
- lfx/components/files_and_knowledge/ingestion.py +694 -0
- lfx/components/files_and_knowledge/retrieval.py +264 -0
- lfx/components/files_and_knowledge/save_file.py +746 -0
- lfx/components/firecrawl/__init__.py +43 -0
- lfx/components/firecrawl/firecrawl_crawl_api.py +88 -0
- lfx/components/firecrawl/firecrawl_extract_api.py +136 -0
- lfx/components/firecrawl/firecrawl_map_api.py +89 -0
- lfx/components/firecrawl/firecrawl_scrape_api.py +73 -0
- lfx/components/flow_controls/__init__.py +58 -0
- lfx/components/flow_controls/conditional_router.py +208 -0
- lfx/components/flow_controls/data_conditional_router.py +126 -0
- lfx/components/flow_controls/flow_tool.py +111 -0
- lfx/components/flow_controls/listen.py +29 -0
- lfx/components/flow_controls/loop.py +163 -0
- lfx/components/flow_controls/notify.py +88 -0
- lfx/components/flow_controls/pass_message.py +36 -0
- lfx/components/flow_controls/run_flow.py +108 -0
- lfx/components/flow_controls/sub_flow.py +115 -0
- lfx/components/git/__init__.py +4 -0
- lfx/components/git/git.py +262 -0
- lfx/components/git/gitextractor.py +196 -0
- lfx/components/glean/__init__.py +3 -0
- lfx/components/glean/glean_search_api.py +173 -0
- lfx/components/google/__init__.py +17 -0
- lfx/components/google/gmail.py +193 -0
- lfx/components/google/google_bq_sql_executor.py +157 -0
- lfx/components/google/google_drive.py +92 -0
- lfx/components/google/google_drive_search.py +152 -0
- lfx/components/google/google_generative_ai.py +144 -0
- lfx/components/google/google_generative_ai_embeddings.py +141 -0
- lfx/components/google/google_oauth_token.py +89 -0
- lfx/components/google/google_search_api_core.py +68 -0
- lfx/components/google/google_serper_api_core.py +74 -0
- lfx/components/groq/__init__.py +34 -0
- lfx/components/groq/groq.py +143 -0
- lfx/components/helpers/__init__.py +154 -0
- lfx/components/homeassistant/__init__.py +7 -0
- lfx/components/homeassistant/home_assistant_control.py +152 -0
- lfx/components/homeassistant/list_home_assistant_states.py +137 -0
- lfx/components/huggingface/__init__.py +37 -0
- lfx/components/huggingface/huggingface.py +199 -0
- lfx/components/huggingface/huggingface_inference_api.py +106 -0
- lfx/components/ibm/__init__.py +34 -0
- lfx/components/ibm/watsonx.py +207 -0
- lfx/components/ibm/watsonx_embeddings.py +135 -0
- lfx/components/icosacomputing/__init__.py +5 -0
- lfx/components/icosacomputing/combinatorial_reasoner.py +84 -0
- lfx/components/input_output/__init__.py +40 -0
- lfx/components/input_output/chat.py +109 -0
- lfx/components/input_output/chat_output.py +184 -0
- lfx/components/input_output/text.py +27 -0
- lfx/components/input_output/text_output.py +29 -0
- lfx/components/input_output/webhook.py +56 -0
- lfx/components/jigsawstack/__init__.py +23 -0
- lfx/components/jigsawstack/ai_scrape.py +126 -0
- lfx/components/jigsawstack/ai_web_search.py +136 -0
- lfx/components/jigsawstack/file_read.py +115 -0
- lfx/components/jigsawstack/file_upload.py +94 -0
- lfx/components/jigsawstack/image_generation.py +205 -0
- lfx/components/jigsawstack/nsfw.py +60 -0
- lfx/components/jigsawstack/object_detection.py +124 -0
- lfx/components/jigsawstack/sentiment.py +112 -0
- lfx/components/jigsawstack/text_to_sql.py +90 -0
- lfx/components/jigsawstack/text_translate.py +77 -0
- lfx/components/jigsawstack/vocr.py +107 -0
- lfx/components/knowledge_bases/__init__.py +89 -0
- lfx/components/langchain_utilities/__init__.py +109 -0
- lfx/components/langchain_utilities/character.py +53 -0
- lfx/components/langchain_utilities/conversation.py +59 -0
- lfx/components/langchain_utilities/csv_agent.py +175 -0
- lfx/components/langchain_utilities/fake_embeddings.py +26 -0
- lfx/components/langchain_utilities/html_link_extractor.py +35 -0
- lfx/components/langchain_utilities/json_agent.py +100 -0
- lfx/components/langchain_utilities/langchain_hub.py +126 -0
- lfx/components/langchain_utilities/language_recursive.py +49 -0
- lfx/components/langchain_utilities/language_semantic.py +138 -0
- lfx/components/langchain_utilities/llm_checker.py +39 -0
- lfx/components/langchain_utilities/llm_math.py +42 -0
- lfx/components/langchain_utilities/natural_language.py +61 -0
- lfx/components/langchain_utilities/openai_tools.py +53 -0
- lfx/components/langchain_utilities/openapi.py +48 -0
- lfx/components/langchain_utilities/recursive_character.py +60 -0
- lfx/components/langchain_utilities/retrieval_qa.py +83 -0
- lfx/components/langchain_utilities/runnable_executor.py +137 -0
- lfx/components/langchain_utilities/self_query.py +80 -0
- lfx/components/langchain_utilities/spider.py +142 -0
- lfx/components/langchain_utilities/sql.py +40 -0
- lfx/components/langchain_utilities/sql_database.py +35 -0
- lfx/components/langchain_utilities/sql_generator.py +78 -0
- lfx/components/langchain_utilities/tool_calling.py +59 -0
- lfx/components/langchain_utilities/vector_store_info.py +49 -0
- lfx/components/langchain_utilities/vector_store_router.py +33 -0
- lfx/components/langchain_utilities/xml_agent.py +71 -0
- lfx/components/langwatch/__init__.py +3 -0
- lfx/components/langwatch/langwatch.py +278 -0
- lfx/components/link_extractors/__init__.py +3 -0
- lfx/components/llm_operations/__init__.py +46 -0
- lfx/components/llm_operations/batch_run.py +205 -0
- lfx/components/llm_operations/lambda_filter.py +218 -0
- lfx/components/llm_operations/llm_conditional_router.py +421 -0
- lfx/components/llm_operations/llm_selector.py +499 -0
- lfx/components/llm_operations/structured_output.py +244 -0
- lfx/components/lmstudio/__init__.py +34 -0
- lfx/components/lmstudio/lmstudioembeddings.py +89 -0
- lfx/components/lmstudio/lmstudiomodel.py +133 -0
- lfx/components/logic/__init__.py +181 -0
- lfx/components/maritalk/__init__.py +32 -0
- lfx/components/maritalk/maritalk.py +52 -0
- lfx/components/mem0/__init__.py +3 -0
- lfx/components/mem0/mem0_chat_memory.py +147 -0
- lfx/components/milvus/__init__.py +34 -0
- lfx/components/milvus/milvus.py +115 -0
- lfx/components/mistral/__init__.py +37 -0
- lfx/components/mistral/mistral.py +114 -0
- lfx/components/mistral/mistral_embeddings.py +58 -0
- lfx/components/models/__init__.py +89 -0
- lfx/components/models_and_agents/__init__.py +49 -0
- lfx/components/models_and_agents/agent.py +644 -0
- lfx/components/models_and_agents/embedding_model.py +423 -0
- lfx/components/models_and_agents/language_model.py +398 -0
- lfx/components/models_and_agents/mcp_component.py +594 -0
- lfx/components/models_and_agents/memory.py +268 -0
- lfx/components/models_and_agents/prompt.py +67 -0
- lfx/components/mongodb/__init__.py +34 -0
- lfx/components/mongodb/mongodb_atlas.py +213 -0
- lfx/components/needle/__init__.py +3 -0
- lfx/components/needle/needle.py +104 -0
- lfx/components/notdiamond/__init__.py +34 -0
- lfx/components/notdiamond/notdiamond.py +228 -0
- lfx/components/novita/__init__.py +32 -0
- lfx/components/novita/novita.py +130 -0
- lfx/components/nvidia/__init__.py +57 -0
- lfx/components/nvidia/nvidia.py +151 -0
- lfx/components/nvidia/nvidia_embedding.py +77 -0
- lfx/components/nvidia/nvidia_ingest.py +317 -0
- lfx/components/nvidia/nvidia_rerank.py +63 -0
- lfx/components/nvidia/system_assist.py +65 -0
- lfx/components/olivya/__init__.py +3 -0
- lfx/components/olivya/olivya.py +116 -0
- lfx/components/ollama/__init__.py +37 -0
- lfx/components/ollama/ollama.py +548 -0
- lfx/components/ollama/ollama_embeddings.py +103 -0
- lfx/components/openai/__init__.py +37 -0
- lfx/components/openai/openai.py +100 -0
- lfx/components/openai/openai_chat_model.py +176 -0
- lfx/components/openrouter/__init__.py +32 -0
- lfx/components/openrouter/openrouter.py +104 -0
- lfx/components/output_parsers/__init__.py +3 -0
- lfx/components/perplexity/__init__.py +34 -0
- lfx/components/perplexity/perplexity.py +75 -0
- lfx/components/pgvector/__init__.py +34 -0
- lfx/components/pgvector/pgvector.py +72 -0
- lfx/components/pinecone/__init__.py +34 -0
- lfx/components/pinecone/pinecone.py +134 -0
- lfx/components/processing/__init__.py +72 -0
- lfx/components/processing/alter_metadata.py +109 -0
- lfx/components/processing/combine_text.py +40 -0
- lfx/components/processing/converter.py +248 -0
- lfx/components/processing/create_data.py +111 -0
- lfx/components/processing/create_list.py +40 -0
- lfx/components/processing/data_operations.py +528 -0
- lfx/components/processing/data_to_dataframe.py +71 -0
- lfx/components/processing/dataframe_operations.py +313 -0
- lfx/components/processing/dataframe_to_toolset.py +259 -0
- lfx/components/processing/dynamic_create_data.py +357 -0
- lfx/components/processing/extract_key.py +54 -0
- lfx/components/processing/filter_data.py +43 -0
- lfx/components/processing/filter_data_values.py +89 -0
- lfx/components/processing/json_cleaner.py +104 -0
- lfx/components/processing/merge_data.py +91 -0
- lfx/components/processing/message_to_data.py +37 -0
- lfx/components/processing/output_parser.py +46 -0
- lfx/components/processing/parse_data.py +71 -0
- lfx/components/processing/parse_dataframe.py +69 -0
- lfx/components/processing/parse_json_data.py +91 -0
- lfx/components/processing/parser.py +148 -0
- lfx/components/processing/regex.py +83 -0
- lfx/components/processing/select_data.py +49 -0
- lfx/components/processing/split_text.py +141 -0
- lfx/components/processing/store_message.py +91 -0
- lfx/components/processing/update_data.py +161 -0
- lfx/components/prototypes/__init__.py +35 -0
- lfx/components/prototypes/python_function.py +73 -0
- lfx/components/qdrant/__init__.py +34 -0
- lfx/components/qdrant/qdrant.py +109 -0
- lfx/components/redis/__init__.py +37 -0
- lfx/components/redis/redis.py +89 -0
- lfx/components/redis/redis_chat.py +43 -0
- lfx/components/sambanova/__init__.py +32 -0
- lfx/components/sambanova/sambanova.py +84 -0
- lfx/components/scrapegraph/__init__.py +40 -0
- lfx/components/scrapegraph/scrapegraph_markdownify_api.py +64 -0
- lfx/components/scrapegraph/scrapegraph_search_api.py +64 -0
- lfx/components/scrapegraph/scrapegraph_smart_scraper_api.py +71 -0
- lfx/components/searchapi/__init__.py +34 -0
- lfx/components/searchapi/search.py +79 -0
- lfx/components/serpapi/__init__.py +3 -0
- lfx/components/serpapi/serp.py +115 -0
- lfx/components/supabase/__init__.py +34 -0
- lfx/components/supabase/supabase.py +76 -0
- lfx/components/tavily/__init__.py +4 -0
- lfx/components/tavily/tavily_extract.py +117 -0
- lfx/components/tavily/tavily_search.py +212 -0
- lfx/components/textsplitters/__init__.py +3 -0
- lfx/components/toolkits/__init__.py +3 -0
- lfx/components/tools/__init__.py +66 -0
- lfx/components/tools/calculator.py +109 -0
- lfx/components/tools/google_search_api.py +45 -0
- lfx/components/tools/google_serper_api.py +115 -0
- lfx/components/tools/python_code_structured_tool.py +328 -0
- lfx/components/tools/python_repl.py +98 -0
- lfx/components/tools/search_api.py +88 -0
- lfx/components/tools/searxng.py +145 -0
- lfx/components/tools/serp_api.py +120 -0
- lfx/components/tools/tavily_search_tool.py +345 -0
- lfx/components/tools/wikidata_api.py +103 -0
- lfx/components/tools/wikipedia_api.py +50 -0
- lfx/components/tools/yahoo_finance.py +130 -0
- lfx/components/twelvelabs/__init__.py +52 -0
- lfx/components/twelvelabs/convert_astra_results.py +84 -0
- lfx/components/twelvelabs/pegasus_index.py +311 -0
- lfx/components/twelvelabs/split_video.py +301 -0
- lfx/components/twelvelabs/text_embeddings.py +57 -0
- lfx/components/twelvelabs/twelvelabs_pegasus.py +408 -0
- lfx/components/twelvelabs/video_embeddings.py +100 -0
- lfx/components/twelvelabs/video_file.py +191 -0
- lfx/components/unstructured/__init__.py +3 -0
- lfx/components/unstructured/unstructured.py +121 -0
- lfx/components/upstash/__init__.py +34 -0
- lfx/components/upstash/upstash.py +124 -0
- lfx/components/utilities/__init__.py +43 -0
- lfx/components/utilities/calculator_core.py +89 -0
- lfx/components/utilities/current_date.py +42 -0
- lfx/components/utilities/id_generator.py +42 -0
- lfx/components/utilities/python_repl_core.py +98 -0
- lfx/components/vectara/__init__.py +37 -0
- lfx/components/vectara/vectara.py +97 -0
- lfx/components/vectara/vectara_rag.py +164 -0
- lfx/components/vectorstores/__init__.py +34 -0
- lfx/components/vectorstores/local_db.py +270 -0
- lfx/components/vertexai/__init__.py +37 -0
- lfx/components/vertexai/vertexai.py +71 -0
- lfx/components/vertexai/vertexai_embeddings.py +67 -0
- lfx/components/vlmrun/__init__.py +34 -0
- lfx/components/vlmrun/vlmrun_transcription.py +224 -0
- lfx/components/weaviate/__init__.py +34 -0
- lfx/components/weaviate/weaviate.py +89 -0
- lfx/components/wikipedia/__init__.py +4 -0
- lfx/components/wikipedia/wikidata.py +86 -0
- lfx/components/wikipedia/wikipedia.py +53 -0
- lfx/components/wolframalpha/__init__.py +3 -0
- lfx/components/wolframalpha/wolfram_alpha_api.py +54 -0
- lfx/components/xai/__init__.py +32 -0
- lfx/components/xai/xai.py +167 -0
- lfx/components/yahoosearch/__init__.py +3 -0
- lfx/components/yahoosearch/yahoo.py +137 -0
- lfx/components/youtube/__init__.py +52 -0
- lfx/components/youtube/channel.py +227 -0
- lfx/components/youtube/comments.py +231 -0
- lfx/components/youtube/playlist.py +33 -0
- lfx/components/youtube/search.py +120 -0
- lfx/components/youtube/trending.py +285 -0
- lfx/components/youtube/video_details.py +263 -0
- lfx/components/youtube/youtube_transcripts.py +206 -0
- lfx/components/zep/__init__.py +3 -0
- lfx/components/zep/zep.py +45 -0
- lfx/constants.py +6 -0
- lfx/custom/__init__.py +7 -0
- lfx/custom/attributes.py +87 -0
- lfx/custom/code_parser/__init__.py +3 -0
- lfx/custom/code_parser/code_parser.py +361 -0
- lfx/custom/custom_component/__init__.py +0 -0
- lfx/custom/custom_component/base_component.py +128 -0
- lfx/custom/custom_component/component.py +1890 -0
- lfx/custom/custom_component/component_with_cache.py +8 -0
- lfx/custom/custom_component/custom_component.py +650 -0
- lfx/custom/dependency_analyzer.py +165 -0
- lfx/custom/directory_reader/__init__.py +3 -0
- lfx/custom/directory_reader/directory_reader.py +359 -0
- lfx/custom/directory_reader/utils.py +171 -0
- lfx/custom/eval.py +12 -0
- lfx/custom/schema.py +32 -0
- lfx/custom/tree_visitor.py +21 -0
- lfx/custom/utils.py +877 -0
- lfx/custom/validate.py +523 -0
- lfx/events/__init__.py +1 -0
- lfx/events/event_manager.py +110 -0
- lfx/exceptions/__init__.py +0 -0
- lfx/exceptions/component.py +15 -0
- lfx/field_typing/__init__.py +91 -0
- lfx/field_typing/constants.py +216 -0
- lfx/field_typing/range_spec.py +35 -0
- lfx/graph/__init__.py +6 -0
- lfx/graph/edge/__init__.py +0 -0
- lfx/graph/edge/base.py +300 -0
- lfx/graph/edge/schema.py +119 -0
- lfx/graph/edge/utils.py +0 -0
- lfx/graph/graph/__init__.py +0 -0
- lfx/graph/graph/ascii.py +202 -0
- lfx/graph/graph/base.py +2298 -0
- lfx/graph/graph/constants.py +63 -0
- lfx/graph/graph/runnable_vertices_manager.py +133 -0
- lfx/graph/graph/schema.py +53 -0
- lfx/graph/graph/state_model.py +66 -0
- lfx/graph/graph/utils.py +1024 -0
- lfx/graph/schema.py +75 -0
- lfx/graph/state/__init__.py +0 -0
- lfx/graph/state/model.py +250 -0
- lfx/graph/utils.py +206 -0
- lfx/graph/vertex/__init__.py +0 -0
- lfx/graph/vertex/base.py +826 -0
- lfx/graph/vertex/constants.py +0 -0
- lfx/graph/vertex/exceptions.py +4 -0
- lfx/graph/vertex/param_handler.py +316 -0
- lfx/graph/vertex/schema.py +26 -0
- lfx/graph/vertex/utils.py +19 -0
- lfx/graph/vertex/vertex_types.py +489 -0
- lfx/helpers/__init__.py +141 -0
- lfx/helpers/base_model.py +71 -0
- lfx/helpers/custom.py +13 -0
- lfx/helpers/data.py +167 -0
- lfx/helpers/flow.py +308 -0
- lfx/inputs/__init__.py +68 -0
- lfx/inputs/constants.py +2 -0
- lfx/inputs/input_mixin.py +352 -0
- lfx/inputs/inputs.py +718 -0
- lfx/inputs/validators.py +19 -0
- lfx/interface/__init__.py +6 -0
- lfx/interface/components.py +897 -0
- lfx/interface/importing/__init__.py +5 -0
- lfx/interface/importing/utils.py +39 -0
- lfx/interface/initialize/__init__.py +3 -0
- lfx/interface/initialize/loading.py +317 -0
- lfx/interface/listing.py +26 -0
- lfx/interface/run.py +16 -0
- lfx/interface/utils.py +111 -0
- lfx/io/__init__.py +63 -0
- lfx/io/schema.py +295 -0
- lfx/load/__init__.py +8 -0
- lfx/load/load.py +256 -0
- lfx/load/utils.py +99 -0
- lfx/log/__init__.py +5 -0
- lfx/log/logger.py +411 -0
- lfx/logging/__init__.py +11 -0
- lfx/logging/logger.py +24 -0
- lfx/memory/__init__.py +70 -0
- lfx/memory/stubs.py +302 -0
- lfx/processing/__init__.py +1 -0
- lfx/processing/process.py +238 -0
- lfx/processing/utils.py +25 -0
- lfx/py.typed +0 -0
- lfx/schema/__init__.py +66 -0
- lfx/schema/artifact.py +83 -0
- lfx/schema/content_block.py +62 -0
- lfx/schema/content_types.py +91 -0
- lfx/schema/cross_module.py +80 -0
- lfx/schema/data.py +309 -0
- lfx/schema/dataframe.py +210 -0
- lfx/schema/dotdict.py +74 -0
- lfx/schema/encoders.py +13 -0
- lfx/schema/graph.py +47 -0
- lfx/schema/image.py +184 -0
- lfx/schema/json_schema.py +186 -0
- lfx/schema/log.py +62 -0
- lfx/schema/message.py +493 -0
- lfx/schema/openai_responses_schemas.py +74 -0
- lfx/schema/properties.py +41 -0
- lfx/schema/schema.py +180 -0
- lfx/schema/serialize.py +13 -0
- lfx/schema/table.py +142 -0
- lfx/schema/validators.py +114 -0
- lfx/serialization/__init__.py +5 -0
- lfx/serialization/constants.py +2 -0
- lfx/serialization/serialization.py +314 -0
- lfx/services/__init__.py +26 -0
- lfx/services/base.py +28 -0
- lfx/services/cache/__init__.py +6 -0
- lfx/services/cache/base.py +183 -0
- lfx/services/cache/service.py +166 -0
- lfx/services/cache/utils.py +169 -0
- lfx/services/chat/__init__.py +1 -0
- lfx/services/chat/config.py +2 -0
- lfx/services/chat/schema.py +10 -0
- lfx/services/database/__init__.py +5 -0
- lfx/services/database/service.py +25 -0
- lfx/services/deps.py +194 -0
- lfx/services/factory.py +19 -0
- lfx/services/initialize.py +19 -0
- lfx/services/interfaces.py +103 -0
- lfx/services/manager.py +185 -0
- lfx/services/mcp_composer/__init__.py +6 -0
- lfx/services/mcp_composer/factory.py +16 -0
- lfx/services/mcp_composer/service.py +1441 -0
- lfx/services/schema.py +21 -0
- lfx/services/session.py +87 -0
- lfx/services/settings/__init__.py +3 -0
- lfx/services/settings/auth.py +133 -0
- lfx/services/settings/base.py +668 -0
- lfx/services/settings/constants.py +43 -0
- lfx/services/settings/factory.py +23 -0
- lfx/services/settings/feature_flags.py +11 -0
- lfx/services/settings/service.py +35 -0
- lfx/services/settings/utils.py +40 -0
- lfx/services/shared_component_cache/__init__.py +1 -0
- lfx/services/shared_component_cache/factory.py +30 -0
- lfx/services/shared_component_cache/service.py +9 -0
- lfx/services/storage/__init__.py +5 -0
- lfx/services/storage/local.py +185 -0
- lfx/services/storage/service.py +177 -0
- lfx/services/tracing/__init__.py +1 -0
- lfx/services/tracing/service.py +21 -0
- lfx/settings.py +6 -0
- lfx/template/__init__.py +6 -0
- lfx/template/field/__init__.py +0 -0
- lfx/template/field/base.py +260 -0
- lfx/template/field/prompt.py +15 -0
- lfx/template/frontend_node/__init__.py +6 -0
- lfx/template/frontend_node/base.py +214 -0
- lfx/template/frontend_node/constants.py +65 -0
- lfx/template/frontend_node/custom_components.py +79 -0
- lfx/template/template/__init__.py +0 -0
- lfx/template/template/base.py +100 -0
- lfx/template/utils.py +217 -0
- lfx/type_extraction/__init__.py +19 -0
- lfx/type_extraction/type_extraction.py +75 -0
- lfx/type_extraction.py +80 -0
- lfx/utils/__init__.py +1 -0
- lfx/utils/async_helpers.py +42 -0
- lfx/utils/component_utils.py +154 -0
- lfx/utils/concurrency.py +60 -0
- lfx/utils/connection_string_parser.py +11 -0
- lfx/utils/constants.py +233 -0
- lfx/utils/data_structure.py +212 -0
- lfx/utils/exceptions.py +22 -0
- lfx/utils/helpers.py +34 -0
- lfx/utils/image.py +79 -0
- lfx/utils/langflow_utils.py +52 -0
- lfx/utils/lazy_load.py +15 -0
- lfx/utils/request_utils.py +18 -0
- lfx/utils/schemas.py +139 -0
- lfx/utils/ssrf_protection.py +384 -0
- lfx/utils/util.py +626 -0
- lfx/utils/util_strings.py +56 -0
- lfx/utils/validate_cloud.py +26 -0
- lfx/utils/version.py +24 -0
- lfx_nightly-0.2.0.dev25.dist-info/METADATA +312 -0
- lfx_nightly-0.2.0.dev25.dist-info/RECORD +769 -0
- lfx_nightly-0.2.0.dev25.dist-info/WHEEL +4 -0
- lfx_nightly-0.2.0.dev25.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Add helper functions for each event type
|
|
2
|
+
import asyncio
|
|
3
|
+
from collections.abc import AsyncIterator
|
|
4
|
+
from time import perf_counter
|
|
5
|
+
from typing import Any, Protocol
|
|
6
|
+
|
|
7
|
+
from langchain_core.agents import AgentFinish
|
|
8
|
+
from langchain_core.messages import AIMessageChunk, BaseMessage
|
|
9
|
+
from typing_extensions import TypedDict
|
|
10
|
+
|
|
11
|
+
from lfx.schema.content_block import ContentBlock
|
|
12
|
+
from lfx.schema.content_types import TextContent, ToolContent
|
|
13
|
+
from lfx.schema.log import OnTokenFunctionType, SendMessageFunctionType
|
|
14
|
+
from lfx.schema.message import Message
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ExceptionWithMessageError(Exception):
|
|
18
|
+
def __init__(self, agent_message: Message, message: str):
|
|
19
|
+
self.agent_message = agent_message
|
|
20
|
+
super().__init__(message)
|
|
21
|
+
self.message = message
|
|
22
|
+
|
|
23
|
+
def __str__(self):
|
|
24
|
+
return (
|
|
25
|
+
f"Agent message: {self.agent_message.text} \nError: {self.message}."
|
|
26
|
+
if self.agent_message.error or self.agent_message.text
|
|
27
|
+
else f"{self.message}."
|
|
28
|
+
)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class InputDict(TypedDict):
|
|
32
|
+
input: str
|
|
33
|
+
chat_history: list[BaseMessage]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _build_agent_input_text_content(agent_input_dict: InputDict) -> str:
|
|
37
|
+
final_input = agent_input_dict.get("input", "")
|
|
38
|
+
return f"{final_input}"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _calculate_duration(start_time: float) -> int:
|
|
42
|
+
"""Calculate duration in milliseconds from start time to now."""
|
|
43
|
+
# Handle the calculation
|
|
44
|
+
current_time = perf_counter()
|
|
45
|
+
if isinstance(start_time, int):
|
|
46
|
+
# If we got an integer, treat it as milliseconds
|
|
47
|
+
duration = current_time - (start_time / 1000)
|
|
48
|
+
result = int(duration * 1000)
|
|
49
|
+
else:
|
|
50
|
+
# If we got a float, treat it as perf_counter time
|
|
51
|
+
result = int((current_time - start_time) * 1000)
|
|
52
|
+
|
|
53
|
+
return result
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
async def handle_on_chain_start(
|
|
57
|
+
event: dict[str, Any],
|
|
58
|
+
agent_message: Message,
|
|
59
|
+
send_message_callback: SendMessageFunctionType,
|
|
60
|
+
send_token_callback: OnTokenFunctionType | None, # noqa: ARG001
|
|
61
|
+
start_time: float,
|
|
62
|
+
*,
|
|
63
|
+
had_streaming: bool = False, # noqa: ARG001
|
|
64
|
+
message_id: str | None = None, # noqa: ARG001
|
|
65
|
+
) -> tuple[Message, float]:
|
|
66
|
+
# Create content blocks if they don't exist
|
|
67
|
+
if not agent_message.content_blocks:
|
|
68
|
+
agent_message.content_blocks = [ContentBlock(title="Agent Steps", contents=[])]
|
|
69
|
+
|
|
70
|
+
if event["data"].get("input"):
|
|
71
|
+
input_data = event["data"].get("input")
|
|
72
|
+
if isinstance(input_data, dict) and "input" in input_data:
|
|
73
|
+
# Cast the input_data to InputDict
|
|
74
|
+
input_message = input_data.get("input", "")
|
|
75
|
+
if isinstance(input_message, BaseMessage):
|
|
76
|
+
input_message = input_message.text()
|
|
77
|
+
elif not isinstance(input_message, str):
|
|
78
|
+
input_message = str(input_message)
|
|
79
|
+
|
|
80
|
+
input_dict: InputDict = {
|
|
81
|
+
"input": input_message,
|
|
82
|
+
"chat_history": input_data.get("chat_history", []),
|
|
83
|
+
}
|
|
84
|
+
text_content = TextContent(
|
|
85
|
+
type="text",
|
|
86
|
+
text=_build_agent_input_text_content(input_dict),
|
|
87
|
+
duration=_calculate_duration(start_time),
|
|
88
|
+
header={"title": "Input", "icon": "MessageSquare"},
|
|
89
|
+
)
|
|
90
|
+
agent_message.content_blocks[0].contents.append(text_content)
|
|
91
|
+
agent_message = await send_message_callback(message=agent_message, skip_db_update=True)
|
|
92
|
+
start_time = perf_counter()
|
|
93
|
+
return agent_message, start_time
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _extract_output_text(output: str | list) -> str:
|
|
97
|
+
if isinstance(output, str):
|
|
98
|
+
return output
|
|
99
|
+
if isinstance(output, list) and len(output) == 0:
|
|
100
|
+
return ""
|
|
101
|
+
|
|
102
|
+
# Handle lists of various lengths and formats
|
|
103
|
+
if isinstance(output, list):
|
|
104
|
+
# Handle single item lists
|
|
105
|
+
if len(output) == 1:
|
|
106
|
+
item = output[0]
|
|
107
|
+
if isinstance(item, str):
|
|
108
|
+
return item
|
|
109
|
+
if isinstance(item, dict):
|
|
110
|
+
if "text" in item:
|
|
111
|
+
return item["text"] or ""
|
|
112
|
+
if "content" in item:
|
|
113
|
+
return str(item["content"])
|
|
114
|
+
if "message" in item:
|
|
115
|
+
return str(item["message"])
|
|
116
|
+
|
|
117
|
+
# Special case handling for non-text-like dicts
|
|
118
|
+
if (
|
|
119
|
+
item.get("type") == "tool_use" # Handle tool use items
|
|
120
|
+
or ("index" in item and len(item) == 1) # Handle index-only items
|
|
121
|
+
or "partial_json" in item # Handle partial json items
|
|
122
|
+
# Handle index-only items
|
|
123
|
+
or ("index" in item and not any(k in item for k in ("text", "content", "message")))
|
|
124
|
+
# Handle other metadata-only chunks that don't contain meaningful text
|
|
125
|
+
or not any(key in item for key in ["text", "content", "message"])
|
|
126
|
+
):
|
|
127
|
+
return ""
|
|
128
|
+
|
|
129
|
+
# For any other dict format, return empty string
|
|
130
|
+
return ""
|
|
131
|
+
# For any other single item type (not str or dict), return empty string
|
|
132
|
+
return ""
|
|
133
|
+
|
|
134
|
+
# Handle multiple items - extract text from all text-type items
|
|
135
|
+
text_parts = []
|
|
136
|
+
for item in output:
|
|
137
|
+
if isinstance(item, str):
|
|
138
|
+
text_parts.append(item)
|
|
139
|
+
elif isinstance(item, dict):
|
|
140
|
+
if "text" in item and item["text"] is not None:
|
|
141
|
+
text_parts.append(item["text"])
|
|
142
|
+
# Skip tool_use, index-only, and partial_json items
|
|
143
|
+
elif item.get("type") == "tool_use" or "partial_json" in item or ("index" in item and len(item) == 1):
|
|
144
|
+
continue
|
|
145
|
+
return "".join(text_parts)
|
|
146
|
+
|
|
147
|
+
# If we get here, the format is unexpected but try to be graceful
|
|
148
|
+
return ""
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
async def handle_on_chain_end(
|
|
152
|
+
event: dict[str, Any],
|
|
153
|
+
agent_message: Message,
|
|
154
|
+
send_message_callback: SendMessageFunctionType,
|
|
155
|
+
send_token_callback: OnTokenFunctionType | None, # noqa: ARG001
|
|
156
|
+
start_time: float,
|
|
157
|
+
*,
|
|
158
|
+
had_streaming: bool = False,
|
|
159
|
+
message_id: str | None = None, # noqa: ARG001
|
|
160
|
+
) -> tuple[Message, float]:
|
|
161
|
+
data_output = event["data"].get("output")
|
|
162
|
+
if data_output and isinstance(data_output, AgentFinish) and data_output.return_values.get("output"):
|
|
163
|
+
output = data_output.return_values.get("output")
|
|
164
|
+
|
|
165
|
+
agent_message.text = _extract_output_text(output)
|
|
166
|
+
agent_message.properties.state = "complete"
|
|
167
|
+
# Add duration to the last content if it exists
|
|
168
|
+
if agent_message.content_blocks:
|
|
169
|
+
duration = _calculate_duration(start_time)
|
|
170
|
+
text_content = TextContent(
|
|
171
|
+
type="text",
|
|
172
|
+
text=agent_message.text,
|
|
173
|
+
duration=duration,
|
|
174
|
+
header={"title": "Output", "icon": "MessageSquare"},
|
|
175
|
+
)
|
|
176
|
+
agent_message.content_blocks[0].contents.append(text_content)
|
|
177
|
+
|
|
178
|
+
# Only send final message if we didn't have streaming chunks
|
|
179
|
+
# If we had streaming, frontend already accumulated the chunks
|
|
180
|
+
if not had_streaming:
|
|
181
|
+
agent_message = await send_message_callback(message=agent_message)
|
|
182
|
+
start_time = perf_counter()
|
|
183
|
+
return agent_message, start_time
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
async def handle_on_tool_start(
|
|
187
|
+
event: dict[str, Any],
|
|
188
|
+
agent_message: Message,
|
|
189
|
+
tool_blocks_map: dict[str, ToolContent],
|
|
190
|
+
send_message_callback: SendMessageFunctionType,
|
|
191
|
+
start_time: float,
|
|
192
|
+
) -> tuple[Message, float]:
|
|
193
|
+
tool_name = event["name"]
|
|
194
|
+
tool_input = event["data"].get("input")
|
|
195
|
+
run_id = event.get("run_id", "")
|
|
196
|
+
tool_key = f"{tool_name}_{run_id}"
|
|
197
|
+
|
|
198
|
+
# Create content blocks if they don't exist
|
|
199
|
+
if not agent_message.content_blocks:
|
|
200
|
+
agent_message.content_blocks = [ContentBlock(title="Agent Steps", contents=[])]
|
|
201
|
+
|
|
202
|
+
duration = _calculate_duration(start_time)
|
|
203
|
+
new_start_time = perf_counter() # Get new start time for next operation
|
|
204
|
+
|
|
205
|
+
# Create new tool content with the input exactly as received
|
|
206
|
+
tool_content = ToolContent(
|
|
207
|
+
type="tool_use",
|
|
208
|
+
name=tool_name,
|
|
209
|
+
tool_input=tool_input,
|
|
210
|
+
output=None,
|
|
211
|
+
error=None,
|
|
212
|
+
header={"title": f"Accessing **{tool_name}**", "icon": "Hammer"},
|
|
213
|
+
duration=duration, # Store the actual duration
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
# Store in map and append to message
|
|
217
|
+
tool_blocks_map[tool_key] = tool_content
|
|
218
|
+
agent_message.content_blocks[0].contents.append(tool_content)
|
|
219
|
+
|
|
220
|
+
agent_message = await send_message_callback(message=agent_message, skip_db_update=True)
|
|
221
|
+
if agent_message.content_blocks and agent_message.content_blocks[0].contents:
|
|
222
|
+
tool_blocks_map[tool_key] = agent_message.content_blocks[0].contents[-1]
|
|
223
|
+
return agent_message, new_start_time
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
async def handle_on_tool_end(
|
|
227
|
+
event: dict[str, Any],
|
|
228
|
+
agent_message: Message,
|
|
229
|
+
tool_blocks_map: dict[str, ToolContent],
|
|
230
|
+
send_message_callback: SendMessageFunctionType,
|
|
231
|
+
start_time: float,
|
|
232
|
+
) -> tuple[Message, float]:
|
|
233
|
+
run_id = event.get("run_id", "")
|
|
234
|
+
tool_name = event.get("name", "")
|
|
235
|
+
tool_key = f"{tool_name}_{run_id}"
|
|
236
|
+
tool_content = tool_blocks_map.get(tool_key)
|
|
237
|
+
|
|
238
|
+
if tool_content and isinstance(tool_content, ToolContent):
|
|
239
|
+
# Call send_message_callback first to get the updated message structure
|
|
240
|
+
agent_message = await send_message_callback(message=agent_message, skip_db_update=True)
|
|
241
|
+
new_start_time = perf_counter()
|
|
242
|
+
|
|
243
|
+
# Now find and update the tool content in the current message
|
|
244
|
+
duration = _calculate_duration(start_time)
|
|
245
|
+
tool_key = f"{tool_name}_{run_id}"
|
|
246
|
+
|
|
247
|
+
# Find the corresponding tool content in the updated message
|
|
248
|
+
updated_tool_content = None
|
|
249
|
+
if agent_message.content_blocks and agent_message.content_blocks[0].contents:
|
|
250
|
+
for content in agent_message.content_blocks[0].contents:
|
|
251
|
+
if (
|
|
252
|
+
isinstance(content, ToolContent)
|
|
253
|
+
and content.name == tool_name
|
|
254
|
+
and content.tool_input == tool_content.tool_input
|
|
255
|
+
):
|
|
256
|
+
updated_tool_content = content
|
|
257
|
+
break
|
|
258
|
+
|
|
259
|
+
# Update the tool content that's actually in the message
|
|
260
|
+
if updated_tool_content:
|
|
261
|
+
updated_tool_content.duration = duration
|
|
262
|
+
updated_tool_content.header = {"title": f"Executed **{updated_tool_content.name}**", "icon": "Hammer"}
|
|
263
|
+
updated_tool_content.output = event["data"].get("output")
|
|
264
|
+
|
|
265
|
+
# Update the map reference
|
|
266
|
+
tool_blocks_map[tool_key] = updated_tool_content
|
|
267
|
+
|
|
268
|
+
return agent_message, new_start_time
|
|
269
|
+
return agent_message, start_time
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
async def handle_on_tool_error(
|
|
273
|
+
event: dict[str, Any],
|
|
274
|
+
agent_message: Message,
|
|
275
|
+
tool_blocks_map: dict[str, ToolContent],
|
|
276
|
+
send_message_callback: SendMessageFunctionType,
|
|
277
|
+
start_time: float,
|
|
278
|
+
) -> tuple[Message, float]:
|
|
279
|
+
run_id = event.get("run_id", "")
|
|
280
|
+
tool_name = event.get("name", "")
|
|
281
|
+
tool_key = f"{tool_name}_{run_id}"
|
|
282
|
+
tool_content = tool_blocks_map.get(tool_key)
|
|
283
|
+
|
|
284
|
+
if tool_content and isinstance(tool_content, ToolContent):
|
|
285
|
+
tool_content.error = event["data"].get("error", "Unknown error")
|
|
286
|
+
tool_content.duration = _calculate_duration(start_time)
|
|
287
|
+
tool_content.header = {"title": f"Error using **{tool_content.name}**", "icon": "Hammer"}
|
|
288
|
+
agent_message = await send_message_callback(message=agent_message, skip_db_update=True)
|
|
289
|
+
start_time = perf_counter()
|
|
290
|
+
return agent_message, start_time
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
async def handle_on_chain_stream(
|
|
294
|
+
event: dict[str, Any],
|
|
295
|
+
agent_message: Message,
|
|
296
|
+
send_message_callback: SendMessageFunctionType, # noqa: ARG001
|
|
297
|
+
send_token_callback: OnTokenFunctionType | None,
|
|
298
|
+
start_time: float,
|
|
299
|
+
*,
|
|
300
|
+
had_streaming: bool = False, # noqa: ARG001
|
|
301
|
+
message_id: str | None = None,
|
|
302
|
+
) -> tuple[Message, float]:
|
|
303
|
+
data_chunk = event["data"].get("chunk", {})
|
|
304
|
+
if isinstance(data_chunk, dict) and data_chunk.get("output"):
|
|
305
|
+
output = data_chunk.get("output")
|
|
306
|
+
if output and isinstance(output, str | list):
|
|
307
|
+
agent_message.text = _extract_output_text(output)
|
|
308
|
+
agent_message.properties.state = "complete"
|
|
309
|
+
# Don't call send_message_callback here - we must update in place
|
|
310
|
+
# in order to keep the message id consistent throughout the stream.
|
|
311
|
+
# The final message will be sent after the loop completes
|
|
312
|
+
start_time = perf_counter()
|
|
313
|
+
elif isinstance(data_chunk, AIMessageChunk):
|
|
314
|
+
output_text = _extract_output_text(data_chunk.content)
|
|
315
|
+
# For streaming, send token event if callback is available
|
|
316
|
+
# Note: we should expect the callback, but we keep it optional for backwards compatibility
|
|
317
|
+
# as of v1.6.5
|
|
318
|
+
if output_text and output_text.strip() and send_token_callback and message_id:
|
|
319
|
+
await asyncio.to_thread(
|
|
320
|
+
send_token_callback,
|
|
321
|
+
data={
|
|
322
|
+
"chunk": output_text,
|
|
323
|
+
"id": str(message_id),
|
|
324
|
+
},
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
if not agent_message.text:
|
|
328
|
+
# Starts the timer when the first message is starting to be generated
|
|
329
|
+
start_time = perf_counter()
|
|
330
|
+
return agent_message, start_time
|
|
331
|
+
|
|
332
|
+
|
|
333
|
+
class ToolEventHandler(Protocol):
|
|
334
|
+
async def __call__(
|
|
335
|
+
self,
|
|
336
|
+
event: dict[str, Any],
|
|
337
|
+
agent_message: Message,
|
|
338
|
+
tool_blocks_map: dict[str, ContentBlock],
|
|
339
|
+
send_message_callback: SendMessageFunctionType,
|
|
340
|
+
start_time: float,
|
|
341
|
+
) -> tuple[Message, float]: ...
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
class ChainEventHandler(Protocol):
|
|
345
|
+
async def __call__(
|
|
346
|
+
self,
|
|
347
|
+
event: dict[str, Any],
|
|
348
|
+
agent_message: Message,
|
|
349
|
+
send_message_callback: SendMessageFunctionType,
|
|
350
|
+
send_token_callback: OnTokenFunctionType | None,
|
|
351
|
+
start_time: float,
|
|
352
|
+
*,
|
|
353
|
+
had_streaming: bool = False,
|
|
354
|
+
message_id: str | None = None,
|
|
355
|
+
) -> tuple[Message, float]: ...
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
EventHandler = ToolEventHandler | ChainEventHandler
|
|
359
|
+
|
|
360
|
+
# Define separate mappings of event types to their respective handler functions
|
|
361
|
+
CHAIN_EVENT_HANDLERS: dict[str, ChainEventHandler] = {
|
|
362
|
+
"on_chain_start": handle_on_chain_start,
|
|
363
|
+
"on_chain_end": handle_on_chain_end,
|
|
364
|
+
"on_chain_stream": handle_on_chain_stream,
|
|
365
|
+
"on_chat_model_stream": handle_on_chain_stream,
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
TOOL_EVENT_HANDLERS: dict[str, ToolEventHandler] = {
|
|
369
|
+
"on_tool_start": handle_on_tool_start,
|
|
370
|
+
"on_tool_end": handle_on_tool_end,
|
|
371
|
+
"on_tool_error": handle_on_tool_error,
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
async def process_agent_events(
|
|
376
|
+
agent_executor: AsyncIterator[dict[str, Any]],
|
|
377
|
+
agent_message: Message,
|
|
378
|
+
send_message_callback: SendMessageFunctionType,
|
|
379
|
+
send_token_callback: OnTokenFunctionType | None = None,
|
|
380
|
+
) -> Message:
|
|
381
|
+
"""Process agent events and return the final output."""
|
|
382
|
+
if isinstance(agent_message.properties, dict):
|
|
383
|
+
agent_message.properties.update({"icon": "Bot", "state": "partial"})
|
|
384
|
+
else:
|
|
385
|
+
agent_message.properties.icon = "Bot"
|
|
386
|
+
agent_message.properties.state = "partial"
|
|
387
|
+
# Store the initial message and capture the message id
|
|
388
|
+
agent_message = await send_message_callback(message=agent_message)
|
|
389
|
+
# Capture the original message id - this must stay consistent throughout if streaming
|
|
390
|
+
# Message may not contain id if the Agent is not connected to a Chat Output (_should_skip_message is True)
|
|
391
|
+
initial_message_id = agent_message.id if hasattr(agent_message, "id") else None
|
|
392
|
+
try:
|
|
393
|
+
# Create a mapping of run_ids to tool contents
|
|
394
|
+
tool_blocks_map: dict[str, ToolContent] = {}
|
|
395
|
+
had_streaming = False
|
|
396
|
+
start_time = perf_counter()
|
|
397
|
+
|
|
398
|
+
async for event in agent_executor:
|
|
399
|
+
if event["event"] in TOOL_EVENT_HANDLERS:
|
|
400
|
+
tool_handler = TOOL_EVENT_HANDLERS[event["event"]]
|
|
401
|
+
# Use skip_db_update=True during streaming to avoid DB round-trips
|
|
402
|
+
agent_message, start_time = await tool_handler(
|
|
403
|
+
event, agent_message, tool_blocks_map, send_message_callback, start_time
|
|
404
|
+
)
|
|
405
|
+
elif event["event"] in CHAIN_EVENT_HANDLERS:
|
|
406
|
+
chain_handler = CHAIN_EVENT_HANDLERS[event["event"]]
|
|
407
|
+
|
|
408
|
+
# Check if this is a streaming event
|
|
409
|
+
if event["event"] in ("on_chain_stream", "on_chat_model_stream"):
|
|
410
|
+
had_streaming = True
|
|
411
|
+
agent_message, start_time = await chain_handler(
|
|
412
|
+
event,
|
|
413
|
+
agent_message,
|
|
414
|
+
send_message_callback,
|
|
415
|
+
send_token_callback,
|
|
416
|
+
start_time,
|
|
417
|
+
had_streaming=had_streaming,
|
|
418
|
+
message_id=initial_message_id,
|
|
419
|
+
)
|
|
420
|
+
else:
|
|
421
|
+
agent_message, start_time = await chain_handler(
|
|
422
|
+
event, agent_message, send_message_callback, None, start_time, had_streaming=had_streaming
|
|
423
|
+
)
|
|
424
|
+
|
|
425
|
+
agent_message.properties.state = "complete"
|
|
426
|
+
# Final DB update with the complete message (skip_db_update=False by default)
|
|
427
|
+
agent_message = await send_message_callback(message=agent_message)
|
|
428
|
+
except Exception as e:
|
|
429
|
+
raise ExceptionWithMessageError(agent_message, str(e)) from e
|
|
430
|
+
return await Message.create(**agent_message.model_dump())
|
lfx/base/agents/utils.py
ADDED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from collections.abc import Callable, Sequence
|
|
3
|
+
from typing import Any
|
|
4
|
+
|
|
5
|
+
from langchain.agents import (
|
|
6
|
+
create_json_chat_agent,
|
|
7
|
+
create_openai_tools_agent,
|
|
8
|
+
create_tool_calling_agent,
|
|
9
|
+
create_xml_agent,
|
|
10
|
+
)
|
|
11
|
+
from langchain.agents.xml.base import render_text_description
|
|
12
|
+
from langchain_core.language_models import BaseLanguageModel
|
|
13
|
+
from langchain_core.messages import BaseMessage
|
|
14
|
+
from langchain_core.prompts import BasePromptTemplate, ChatPromptTemplate
|
|
15
|
+
from langchain_core.tools import BaseTool
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
from lfx.log.logger import logger
|
|
19
|
+
from lfx.schema.data import Data
|
|
20
|
+
from lfx.schema.message import Message
|
|
21
|
+
from lfx.services.cache.base import CacheService
|
|
22
|
+
from lfx.services.cache.utils import CacheMiss
|
|
23
|
+
|
|
24
|
+
from .default_prompts import XML_AGENT_PROMPT
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AgentSpec(BaseModel):
|
|
28
|
+
func: Callable[
|
|
29
|
+
[
|
|
30
|
+
BaseLanguageModel,
|
|
31
|
+
Sequence[BaseTool],
|
|
32
|
+
BasePromptTemplate | ChatPromptTemplate,
|
|
33
|
+
Callable[[list[BaseTool]], str] | None,
|
|
34
|
+
bool | list[str] | None,
|
|
35
|
+
],
|
|
36
|
+
Any,
|
|
37
|
+
]
|
|
38
|
+
prompt: Any | None = None
|
|
39
|
+
fields: list[str]
|
|
40
|
+
hub_repo: str | None = None
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def data_to_messages(data: list[Data | Message]) -> list[BaseMessage]:
|
|
44
|
+
"""Convert a list of data to a list of messages.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
data (List[Data | Message]): The data to convert.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
List[BaseMessage]: The data as messages, filtering out any with empty content.
|
|
51
|
+
"""
|
|
52
|
+
messages = []
|
|
53
|
+
for value in data:
|
|
54
|
+
try:
|
|
55
|
+
lc_message = value.to_lc_message()
|
|
56
|
+
# Only add messages with non-empty content (prevents Anthropic API errors)
|
|
57
|
+
content = lc_message.content
|
|
58
|
+
if content and ((isinstance(content, str) and content.strip()) or (isinstance(content, list) and content)):
|
|
59
|
+
messages.append(lc_message)
|
|
60
|
+
else:
|
|
61
|
+
logger.warning("Skipping message with empty content in chat history")
|
|
62
|
+
except (ValueError, AttributeError) as e:
|
|
63
|
+
logger.warning(f"Failed to convert message to BaseMessage: {e}")
|
|
64
|
+
continue
|
|
65
|
+
return messages
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def validate_and_create_xml_agent(
|
|
69
|
+
llm: BaseLanguageModel,
|
|
70
|
+
tools: Sequence[BaseTool],
|
|
71
|
+
prompt: BasePromptTemplate,
|
|
72
|
+
tools_renderer: Callable[[list[BaseTool]], str] = render_text_description,
|
|
73
|
+
*,
|
|
74
|
+
stop_sequence: bool | list[str] = True,
|
|
75
|
+
):
|
|
76
|
+
return create_xml_agent(
|
|
77
|
+
llm=llm,
|
|
78
|
+
tools=tools,
|
|
79
|
+
prompt=prompt,
|
|
80
|
+
tools_renderer=tools_renderer,
|
|
81
|
+
stop_sequence=stop_sequence,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def validate_and_create_openai_tools_agent(
|
|
86
|
+
llm: BaseLanguageModel,
|
|
87
|
+
tools: Sequence[BaseTool],
|
|
88
|
+
prompt: ChatPromptTemplate,
|
|
89
|
+
_tools_renderer: Callable[[list[BaseTool]], str] = render_text_description,
|
|
90
|
+
*,
|
|
91
|
+
_stop_sequence: bool | list[str] = True,
|
|
92
|
+
):
|
|
93
|
+
return create_openai_tools_agent(
|
|
94
|
+
llm=llm,
|
|
95
|
+
tools=tools,
|
|
96
|
+
prompt=prompt,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def validate_and_create_tool_calling_agent(
|
|
101
|
+
llm: BaseLanguageModel,
|
|
102
|
+
tools: Sequence[BaseTool],
|
|
103
|
+
prompt: ChatPromptTemplate,
|
|
104
|
+
_tools_renderer: Callable[[list[BaseTool]], str] = render_text_description,
|
|
105
|
+
*,
|
|
106
|
+
_stop_sequence: bool | list[str] = True,
|
|
107
|
+
):
|
|
108
|
+
return create_tool_calling_agent(
|
|
109
|
+
llm=llm,
|
|
110
|
+
tools=tools,
|
|
111
|
+
prompt=prompt,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def validate_and_create_json_chat_agent(
|
|
116
|
+
llm: BaseLanguageModel,
|
|
117
|
+
tools: Sequence[BaseTool],
|
|
118
|
+
prompt: ChatPromptTemplate,
|
|
119
|
+
tools_renderer: Callable[[list[BaseTool]], str] = render_text_description,
|
|
120
|
+
*,
|
|
121
|
+
stop_sequence: bool | list[str] = True,
|
|
122
|
+
):
|
|
123
|
+
return create_json_chat_agent(
|
|
124
|
+
llm=llm,
|
|
125
|
+
tools=tools,
|
|
126
|
+
prompt=prompt,
|
|
127
|
+
tools_renderer=tools_renderer,
|
|
128
|
+
stop_sequence=stop_sequence,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
AGENTS: dict[str, AgentSpec] = {
|
|
133
|
+
"Tool Calling Agent": AgentSpec(
|
|
134
|
+
func=validate_and_create_tool_calling_agent,
|
|
135
|
+
prompt=None,
|
|
136
|
+
fields=["llm", "tools", "prompt"],
|
|
137
|
+
hub_repo=None,
|
|
138
|
+
),
|
|
139
|
+
"XML Agent": AgentSpec(
|
|
140
|
+
func=validate_and_create_xml_agent,
|
|
141
|
+
prompt=XML_AGENT_PROMPT, # Ensure XML_AGENT_PROMPT is properly defined and typed.
|
|
142
|
+
fields=["llm", "tools", "prompt", "tools_renderer", "stop_sequence"],
|
|
143
|
+
hub_repo="hwchase17/xml-agent-convo",
|
|
144
|
+
),
|
|
145
|
+
"OpenAI Tools Agent": AgentSpec(
|
|
146
|
+
func=validate_and_create_openai_tools_agent,
|
|
147
|
+
prompt=None,
|
|
148
|
+
fields=["llm", "tools", "prompt"],
|
|
149
|
+
hub_repo=None,
|
|
150
|
+
),
|
|
151
|
+
"JSON Chat Agent": AgentSpec(
|
|
152
|
+
func=validate_and_create_json_chat_agent,
|
|
153
|
+
prompt=None,
|
|
154
|
+
fields=["llm", "tools", "prompt", "tools_renderer", "stop_sequence"],
|
|
155
|
+
hub_repo="hwchase17/react-chat-json",
|
|
156
|
+
),
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def get_agents_list():
|
|
161
|
+
return list(AGENTS.keys())
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def safe_cache_get(cache: CacheService, key, default=None):
|
|
165
|
+
"""Safely get a value from cache, handling CacheMiss objects."""
|
|
166
|
+
try:
|
|
167
|
+
value = cache.get(key)
|
|
168
|
+
if isinstance(value, CacheMiss):
|
|
169
|
+
return default
|
|
170
|
+
except (AttributeError, KeyError, TypeError):
|
|
171
|
+
return default
|
|
172
|
+
else:
|
|
173
|
+
return value
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def safe_cache_set(cache: CacheService, key, value):
|
|
177
|
+
"""Safely set a value in cache, handling potential errors."""
|
|
178
|
+
try:
|
|
179
|
+
cache.set(key, value)
|
|
180
|
+
except (AttributeError, TypeError) as e:
|
|
181
|
+
logger.warning(f"Failed to set cache key '{key}': {e}")
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def maybe_unflatten_dict(flat: dict[str, Any]) -> dict[str, Any]:
|
|
185
|
+
"""If any key looks nested (contains a dot or "[index]"), rebuild the.
|
|
186
|
+
|
|
187
|
+
full nested structure; otherwise return flat as is.
|
|
188
|
+
"""
|
|
189
|
+
# Quick check: do we have any nested keys?
|
|
190
|
+
if not any(re.search(r"\.|\[\d+\]", key) for key in flat):
|
|
191
|
+
return flat
|
|
192
|
+
|
|
193
|
+
# Otherwise, unflatten into dicts/lists
|
|
194
|
+
nested: dict[str, Any] = {}
|
|
195
|
+
array_re = re.compile(r"^(.+)\[(\d+)\]$")
|
|
196
|
+
|
|
197
|
+
for key, val in flat.items():
|
|
198
|
+
parts = key.split(".")
|
|
199
|
+
cur = nested
|
|
200
|
+
for i, part in enumerate(parts):
|
|
201
|
+
m = array_re.match(part)
|
|
202
|
+
# Array segment?
|
|
203
|
+
if m:
|
|
204
|
+
name, idx = m.group(1), int(m.group(2))
|
|
205
|
+
lst = cur.setdefault(name, [])
|
|
206
|
+
# Ensure list is big enough
|
|
207
|
+
while len(lst) <= idx:
|
|
208
|
+
lst.append({})
|
|
209
|
+
if i == len(parts) - 1:
|
|
210
|
+
lst[idx] = val
|
|
211
|
+
else:
|
|
212
|
+
cur = lst[idx]
|
|
213
|
+
# Normal object key
|
|
214
|
+
elif i == len(parts) - 1:
|
|
215
|
+
cur[part] = val
|
|
216
|
+
else:
|
|
217
|
+
cur = cur.setdefault(part, {})
|
|
218
|
+
|
|
219
|
+
return nested
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def get_chat_output_sender_name(self) -> str | None:
|
|
223
|
+
"""Get sender_name from ChatOutput component."""
|
|
224
|
+
if not hasattr(self, "graph") or not self.graph:
|
|
225
|
+
return None
|
|
226
|
+
|
|
227
|
+
for vertex in self.graph.vertices:
|
|
228
|
+
# Safely check if vertex has data attribute, correct type, and raw_params
|
|
229
|
+
if (
|
|
230
|
+
hasattr(vertex, "data")
|
|
231
|
+
and vertex.data.get("type") == "ChatOutput"
|
|
232
|
+
and hasattr(vertex, "raw_params")
|
|
233
|
+
and vertex.raw_params
|
|
234
|
+
):
|
|
235
|
+
return vertex.raw_params.get("sender_name")
|
|
236
|
+
|
|
237
|
+
return None
|
|
File without changes
|