langflow-base-nightly 0.5.0.dev37__py3-none-any.whl → 0.5.0.dev38__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.
- langflow/__main__.py +1 -1
- langflow/alembic/versions/4e5980a44eaa_fix_date_times_again.py +24 -30
- langflow/alembic/versions/58b28437a398_modify_nullable.py +6 -6
- langflow/alembic/versions/79e675cb6752_change_datetime_type.py +24 -30
- langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py +12 -13
- langflow/api/build.py +21 -26
- langflow/api/health_check_router.py +3 -3
- langflow/api/utils.py +3 -3
- langflow/api/v1/callback.py +2 -2
- langflow/api/v1/chat.py +19 -31
- langflow/api/v1/endpoints.py +10 -10
- langflow/api/v1/flows.py +1 -1
- langflow/api/v1/knowledge_bases.py +3 -3
- langflow/api/v1/mcp.py +12 -12
- langflow/api/v1/mcp_projects.py +45 -81
- langflow/api/v1/mcp_utils.py +8 -8
- langflow/api/v1/schemas.py +1 -5
- langflow/api/v1/store.py +1 -1
- langflow/api/v1/validate.py +2 -2
- langflow/api/v1/voice_mode.py +58 -62
- langflow/api/v2/files.py +2 -2
- langflow/api/v2/mcp.py +10 -9
- langflow/base/composio/composio_base.py +21 -2
- langflow/base/data/docling_utils.py +194 -0
- langflow/base/embeddings/aiml_embeddings.py +1 -1
- langflow/base/flow_processing/utils.py +1 -2
- langflow/base/io/__init__.py +0 -1
- langflow/base/langwatch/utils.py +2 -1
- langflow/base/mcp/util.py +49 -47
- langflow/base/prompts/api_utils.py +1 -1
- langflow/base/tools/flow_tool.py +2 -2
- langflow/base/tools/run_flow.py +2 -6
- langflow/components/Notion/add_content_to_page.py +2 -2
- langflow/components/Notion/list_database_properties.py +2 -2
- langflow/components/Notion/list_pages.py +2 -2
- langflow/components/Notion/page_content_viewer.py +2 -2
- langflow/components/Notion/update_page_property.py +1 -1
- langflow/components/agentql/agentql_api.py +2 -10
- langflow/components/agents/agent.py +3 -3
- langflow/components/agents/mcp_component.py +14 -14
- langflow/components/anthropic/anthropic.py +5 -4
- langflow/components/assemblyai/assemblyai_get_subtitles.py +2 -2
- langflow/components/assemblyai/assemblyai_lemur.py +2 -2
- langflow/components/assemblyai/assemblyai_list_transcripts.py +2 -2
- langflow/components/assemblyai/assemblyai_poll_transcript.py +2 -2
- langflow/components/assemblyai/assemblyai_start_transcript.py +2 -2
- langflow/components/data/file.py +575 -55
- langflow/components/data/url.py +1 -1
- langflow/components/datastax/astra_assistant_manager.py +3 -3
- langflow/components/datastax/create_assistant.py +1 -2
- langflow/components/deactivated/merge_data.py +1 -2
- langflow/components/deactivated/sub_flow.py +6 -7
- langflow/components/deactivated/vectara_self_query.py +3 -3
- langflow/components/docling/__init__.py +0 -198
- langflow/components/docling/docling_inline.py +1 -1
- langflow/components/embeddings/text_embedder.py +3 -3
- langflow/components/firecrawl/firecrawl_extract_api.py +2 -9
- langflow/components/google/gmail.py +1 -1
- langflow/components/google/google_generative_ai.py +5 -11
- langflow/components/groq/groq.py +4 -3
- langflow/components/helpers/current_date.py +2 -3
- langflow/components/helpers/memory.py +1 -1
- langflow/components/ibm/watsonx.py +1 -1
- langflow/components/ibm/watsonx_embeddings.py +1 -1
- langflow/components/langwatch/langwatch.py +3 -3
- langflow/components/logic/flow_tool.py +2 -2
- langflow/components/logic/notify.py +1 -1
- langflow/components/logic/run_flow.py +2 -3
- langflow/components/logic/sub_flow.py +4 -5
- langflow/components/mem0/mem0_chat_memory.py +2 -8
- langflow/components/nvidia/nvidia.py +3 -3
- langflow/components/olivya/olivya.py +7 -7
- langflow/components/ollama/ollama.py +8 -6
- langflow/components/processing/batch_run.py +8 -8
- langflow/components/processing/data_operations.py +2 -2
- langflow/components/processing/merge_data.py +1 -2
- langflow/components/processing/message_to_data.py +2 -3
- langflow/components/processing/parse_json_data.py +1 -1
- langflow/components/prototypes/python_function.py +2 -3
- langflow/components/serpapi/serp.py +1 -1
- langflow/components/tavily/tavily_extract.py +1 -1
- langflow/components/tavily/tavily_search.py +1 -1
- langflow/components/tools/calculator.py +2 -2
- langflow/components/tools/python_code_structured_tool.py +3 -10
- langflow/components/tools/python_repl.py +2 -2
- langflow/components/tools/searxng.py +3 -3
- langflow/components/tools/serp_api.py +2 -2
- langflow/components/tools/tavily_search_tool.py +2 -2
- langflow/components/tools/yahoo_finance.py +1 -1
- langflow/components/twelvelabs/video_embeddings.py +4 -4
- langflow/components/vectorstores/local_db.py +1 -1
- langflow/components/yahoosearch/yahoo.py +1 -1
- langflow/components/youtube/trending.py +3 -4
- langflow/custom/attributes.py +2 -1
- langflow/custom/code_parser/code_parser.py +1 -1
- langflow/custom/custom_component/base_component.py +1 -1
- langflow/custom/custom_component/component.py +16 -2
- langflow/custom/directory_reader/directory_reader.py +7 -7
- langflow/custom/directory_reader/utils.py +1 -2
- langflow/custom/utils.py +30 -30
- langflow/events/event_manager.py +1 -1
- langflow/frontend/assets/{SlackIcon-CnvyOamQ.js → SlackIcon-BhW6H3JR.js} +1 -1
- langflow/frontend/assets/{Wikipedia-nyTEXdr2.js → Wikipedia-Dx5jbiy3.js} +1 -1
- langflow/frontend/assets/{Wolfram-BYMQkNSq.js → Wolfram-CIyonzwo.js} +1 -1
- langflow/frontend/assets/{index-HK3bVMYA.js → index-0XQqYgdG.js} +1 -1
- langflow/frontend/assets/{index-BZgXW854.js → index-1Q3VBqKn.js} +1 -1
- langflow/frontend/assets/{index-BQ6NUdMY.js → index-35sspuLu.js} +1 -1
- langflow/frontend/assets/{index-DPCzHdsC.js → index-7hzXChQz.js} +1 -1
- langflow/frontend/assets/{index-CFDvOtKC.js → index-8cuhogZP.js} +1 -1
- langflow/frontend/assets/{index-CYDAYm-i.js → index-B0m53xKd.js} +1 -1
- langflow/frontend/assets/{index-Q9vDw0Xl.js → index-B1XqWJhG.js} +1 -1
- langflow/frontend/assets/{index-Gkrq-vzm.js → index-B3KCdQ91.js} +1 -1
- langflow/frontend/assets/{index-DytJENYD.js → index-B7uEuOPK.js} +1 -1
- langflow/frontend/assets/{index-DkXy1WFo.js → index-B8UR8v-Q.js} +1 -1
- langflow/frontend/assets/{index-BChjg6Az.js → index-BD7Io1hL.js} +6 -6
- langflow/frontend/assets/{index-CyPvTB63.js → index-BDQrd7Tj.js} +1 -1
- langflow/frontend/assets/{index-BbJjt5m4.js → index-BDuk0d7P.js} +1 -1
- langflow/frontend/assets/{index-BBxAPk1y.js → index-BFQ8KFK0.js} +1 -1
- langflow/frontend/assets/{index-BqPpO6KG.js → index-BFf0HTFI.js} +1 -1
- langflow/frontend/assets/{index-yCHsaqs8.js → index-BHhnpSkW.js} +1 -1
- langflow/frontend/assets/{index-Bd6WtbKA.js → index-BKKrUElc.js} +1 -1
- langflow/frontend/assets/{index-DHq8TQPB.js → index-BKeZt2hQ.js} +1 -1
- langflow/frontend/assets/{index-BCCGvqay.js → index-BKlQbl-6.js} +1 -1
- langflow/frontend/assets/{index-Boso-xEw.js → index-BLYw9MK2.js} +1 -1
- langflow/frontend/assets/{index-DmMDPoi0.js → index-BLsVo9iW.js} +1 -1
- langflow/frontend/assets/{index-Car-zdor.js → index-BNQIbda3.js} +1 -1
- langflow/frontend/assets/{index-Dg-63Si_.js → index-BPR2mEFC.js} +1 -1
- langflow/frontend/assets/{index-CTrt1Q_j.js → index-BPfdqCc_.js} +1 -1
- langflow/frontend/assets/{index-CVQmT7ZL.js → index-BQrVDjR1.js} +1 -1
- langflow/frontend/assets/{index-BB15_iOb.js → index-BRmSeoWR.js} +1 -1
- langflow/frontend/assets/{index-BX5D-USa.js → index-BUse-kxM.js} +1 -1
- langflow/frontend/assets/{index-CaQ_H9ww.js → index-BVFaF7HW.js} +1 -1
- langflow/frontend/assets/{index-C26RqKWL.js → index-BWgIWfv2.js} +1 -1
- langflow/frontend/assets/{index-DbMFlnHE.js → index-BWt5xGeA.js} +1 -1
- langflow/frontend/assets/{index-Db71w3lq.js → index-BYhcGLTV.js} +1 -1
- langflow/frontend/assets/{index-DzW2mfkK.js → index-BYjw7Gk3.js} +1 -1
- langflow/frontend/assets/{index-DJB12jIC.js → index-BZFljdMa.js} +1 -1
- langflow/frontend/assets/{index-nVwHLjuV.js → index-BcAgItH4.js} +1 -1
- langflow/frontend/assets/{index-DkelbYy7.js → index-Bct1s6__.js} +1 -1
- langflow/frontend/assets/{index-ChXJpBz4.js → index-Bhv79Zso.js} +1 -1
- langflow/frontend/assets/{index-BxEuHa76.js → index-Bj3lSwvZ.js} +1 -1
- langflow/frontend/assets/{index-BkPYpfgw.js → index-Bk4mTwnI.js} +1 -1
- langflow/frontend/assets/{index-BvT7L317.js → index-BmIx1cws.js} +1 -1
- langflow/frontend/assets/{index-DIDDfmlJ.js → index-BmYJJ5YS.js} +1 -1
- langflow/frontend/assets/{index-C7QWbnLK.js → index-BnAFhkSN.js} +1 -1
- langflow/frontend/assets/{index-CJo_cyWW.js → index-Bo-ww0Bb.js} +1 -1
- langflow/frontend/assets/{index-DjQETUy8.js → index-BpmqDOeZ.js} +1 -1
- langflow/frontend/assets/{index-ya2uXE8v.js → index-BrVhdPZb.js} +1 -1
- langflow/frontend/assets/{index-DCRk27Tp.js → index-BvGQfVBD.js} +1 -1
- langflow/frontend/assets/{index-BTrsh9LS.js → index-Bwi4flFg.js} +1 -1
- langflow/frontend/assets/{index-BRxvproo.js → index-BzoRPtTY.js} +1 -1
- langflow/frontend/assets/{index-BIQQCMvz.js → index-C--IDAyc.js} +1 -1
- langflow/frontend/assets/{index-DfngcQxO.js → index-C0E3_MIK.js} +1 -1
- langflow/frontend/assets/{index-Bvxg4_ux.js → index-C27Jj_26.js} +1 -1
- langflow/frontend/assets/{index-D8lOi1GI.js → index-C2eQmQsn.js} +1 -1
- langflow/frontend/assets/{index-rXV1G1aB.js → index-C8K0r39B.js} +1 -1
- langflow/frontend/assets/{index-B3Sur4Z3.js → index-CEJNWPhA.js} +1 -1
- langflow/frontend/assets/{index-BR0bkVqX.js → index-CFNTYfFK.js} +1 -1
- langflow/frontend/assets/{index-Bnqod3vk.js → index-CMHpjHZl.js} +1 -1
- langflow/frontend/assets/{index-BLGYN-9b.js → index-CSu8KHOi.js} +1 -1
- langflow/frontend/assets/{index-BOB_zsjl.js → index-CUKmGsI6.js} +1 -1
- langflow/frontend/assets/{index-BzEUlaw_.js → index-CWYiSeWV.js} +1 -1
- langflow/frontend/assets/{index-DVlceYFD.js → index-CY7_TBTC.js} +1 -1
- langflow/frontend/assets/{index-D3DDfngy.js → index-CbnWRlYY.js} +1 -1
- langflow/frontend/assets/{index-cvZdgWHQ.js → index-CfPBgkqg.js} +1 -1
- langflow/frontend/assets/{index-Ui4xUImO.js → index-Cg53lrYh.js} +1 -1
- langflow/frontend/assets/{index-C6jri9Wm.js → index-CgU7KF4I.js} +1 -1
- langflow/frontend/assets/{index-BVEZDXxS.js → index-CgwykVGh.js} +1 -1
- langflow/frontend/assets/{index-BOeo01QB.js → index-Ch5r0oW6.js} +1 -1
- langflow/frontend/assets/{index-D6PSjHxP.js → index-CjsommIr.js} +1 -1
- langflow/frontend/assets/{index-pCQ_yw8m.js → index-CkK25zZO.js} +1 -1
- langflow/frontend/assets/{index-BFp_O-c9.js → index-CkjwSTSM.js} +1 -1
- langflow/frontend/assets/{index-Du_18NCU.js → index-CmSFKgiD.js} +1 -1
- langflow/frontend/assets/{index-BvwZfF2i.js → index-Cr5v2ave.js} +1 -1
- langflow/frontend/assets/{index-FUxmznS-.js → index-CrAF-31Y.js} +1 -1
- langflow/frontend/assets/{index-C-2hghRJ.js → index-CsLQiWNf.js} +1 -1
- langflow/frontend/assets/{index-C_TdzfAn.js → index-CuCM7Wu7.js} +1 -1
- langflow/frontend/assets/{index-D5_DsUJc.js → index-Cxy9sEpy.js} +1 -1
- langflow/frontend/assets/{index-C_veJlEb.js → index-CyP3py8K.js} +1 -1
- langflow/frontend/assets/{index-OazXJdEl.js → index-CzHzeZuA.js} +1 -1
- langflow/frontend/assets/{index-CvcEzq4x.js → index-D1oynC8a.js} +1 -1
- langflow/frontend/assets/{index-CZQ9rXNa.js → index-D4tjMhfY.js} +1 -1
- langflow/frontend/assets/{index-B1YN7oMV.js → index-D6CSIrp1.js} +1 -1
- langflow/frontend/assets/{index-DfxYyS3M.js → index-D9kwEzPB.js} +1 -1
- langflow/frontend/assets/{index-BbRm7beF.js → index-DDXsm8tz.js} +1 -1
- langflow/frontend/assets/{index-xuIrH2Dq.js → index-DDhJVVel.js} +1 -1
- langflow/frontend/assets/{index-CmplyEaa.js → index-DH6o91_s.js} +1 -1
- langflow/frontend/assets/{index-DnEGCgih.js → index-DHngW1k8.js} +1 -1
- langflow/frontend/assets/{index-ajRge-Mg.js → index-DIKUsGLF.js} +1 -1
- langflow/frontend/assets/{index-DpClkXIV.js → index-DJESSNJi.js} +1 -1
- langflow/frontend/assets/{index-8WdfSTTz.js → index-DMCWDJOl.js} +1 -1
- langflow/frontend/assets/{index-DZTC5pdT.js → index-DOEvKC2X.js} +1 -1
- langflow/frontend/assets/{index-DysKpOuj.js → index-DOQDkSoK.js} +1 -1
- langflow/frontend/assets/{index-C82JjCPD.js → index-DXAfIEvs.js} +1 -1
- langflow/frontend/assets/{index-D8GJngXa.js → index-DZP_SaHb.js} +1 -1
- langflow/frontend/assets/{index-DIkNW9Cd.js → index-DZxUIhWh.js} +1 -1
- langflow/frontend/assets/{index-DK1Ptcc4.js → index-Dda2u_yz.js} +1 -1
- langflow/frontend/assets/{index-BWmPX4iQ.js → index-Dg8N3NSO.js} +1 -1
- langflow/frontend/assets/{index-CWdkbVsd.js → index-DkGhPNeA.js} +1 -1
- langflow/frontend/assets/{index-DF5VwgU6.js → index-Dka_Rk4-.js} +1 -1
- langflow/frontend/assets/{index-Bsa0xZyL.js → index-DljpLeCW.js} +1 -1
- langflow/frontend/assets/{index-CLPdN-q6.js → index-DnVYJtVO.js} +1 -1
- langflow/frontend/assets/{index-CxvP91st.js → index-DqbzUcI5.js} +1 -1
- langflow/frontend/assets/{index-BIzTEqFh.js → index-Dr6pVDPI.js} +1 -1
- langflow/frontend/assets/{index-tVYiABdp.js → index-DsoX2o1S.js} +1 -1
- langflow/frontend/assets/{index-CCePCqkT.js → index-DwfHWnX7.js} +1 -1
- langflow/frontend/assets/{index-BEMw2Np8.js → index-Dx-Z87KT.js} +1 -1
- langflow/frontend/assets/{index-BRYjyhAd.js → index-DyqITq51.js} +1 -1
- langflow/frontend/assets/{index-l7bzB8Ex.js → index-DzIv3RyR.js} +1 -1
- langflow/frontend/assets/{index-D-9TI74R.js → index-G4ro0MjT.js} +1 -1
- langflow/frontend/assets/{index-CCxGSSTT.js → index-H7J7w7fa.js} +1 -1
- langflow/frontend/assets/{index-_UcqeEjm.js → index-KWY77KfV.js} +1 -1
- langflow/frontend/assets/{index-Dqd4RjYA.js → index-U9GWm1eH.js} +1 -1
- langflow/frontend/assets/{index-Dq5ilsem.js → index-Un9pWxnP.js} +1 -1
- langflow/frontend/assets/{index-BzL_EoKd.js → index-Xi4TplbI.js} +1 -1
- langflow/frontend/assets/{index-LbYjHKkn.js → index-_cbGmjF4.js} +1 -1
- langflow/frontend/assets/{index-DGRMNe9n.js → index-cEXY6V06.js} +1 -1
- langflow/frontend/assets/{index-8yMsjVV2.js → index-dyXKnkMi.js} +1 -1
- langflow/frontend/assets/{index-DKHNourL.js → index-eUkS6iJM.js} +1 -1
- langflow/frontend/assets/{index-Bv8h2Z-q.js → index-ekfMOqrF.js} +1 -1
- langflow/frontend/assets/{index-B748uLP1.js → index-gdb7XMS8.js} +1 -1
- langflow/frontend/assets/{index-CpvYQ0ug.js → index-hZUcL0MZ.js} +1 -1
- langflow/frontend/assets/{index-BIXaW2aY.js → index-kkA-qHB_.js} +1 -1
- langflow/frontend/assets/{index-BhIOhlCH.js → index-mzl9ULw5.js} +1 -1
- langflow/frontend/assets/{index-CYe8Ipef.js → index-oxHBZk2v.js} +1 -1
- langflow/frontend/assets/{index-WPFivmdQ.js → index-p2kStSPe.js} +1 -1
- langflow/frontend/assets/{index-BmX5CoED.js → index-paQEWYGT.js} +1 -1
- langflow/frontend/assets/{index-CpcbQZIF.js → index-r_8gs4nL.js} +1 -1
- langflow/frontend/assets/{index-dcnYpT9N.js → index-uiKla4UR.js} +1 -1
- langflow/frontend/assets/{index-BTEW9e8P.js → index-vJOO5U8M.js} +1 -1
- langflow/frontend/assets/{index-CQMoqLAu.js → index-w72fDjpG.js} +1 -1
- langflow/frontend/assets/{index-Dsps-jKu.js → index-zV82kQ6k.js} +1 -1
- langflow/frontend/assets/lazyIconImports-DTNgvPE-.js +2 -0
- langflow/frontend/assets/{use-post-add-user-BrBYH9eR.js → use-post-add-user-CvtuazTg.js} +1 -1
- langflow/frontend/index.html +1 -1
- langflow/graph/edge/base.py +2 -3
- langflow/graph/graph/base.py +14 -12
- langflow/graph/graph/constants.py +3 -0
- langflow/graph/utils.py +6 -6
- langflow/graph/vertex/base.py +4 -5
- langflow/graph/vertex/param_handler.py +1 -1
- langflow/graph/vertex/vertex_types.py +2 -2
- langflow/helpers/flow.py +1 -1
- langflow/initial_setup/setup.py +32 -30
- langflow/initial_setup/starter_projects/Blog Writer.json +2 -2
- langflow/initial_setup/starter_projects/Custom Component Generator.json +2 -2
- langflow/initial_setup/starter_projects/Document Q&A.json +1 -1
- langflow/initial_setup/starter_projects/Instagram Copywriter.json +3 -3
- langflow/initial_setup/starter_projects/Invoice Summarizer.json +1 -1
- langflow/initial_setup/starter_projects/Knowledge Ingestion.json +2 -2
- langflow/initial_setup/starter_projects/Market Research.json +3 -3
- langflow/initial_setup/starter_projects/Meeting Summary.json +6 -6
- langflow/initial_setup/starter_projects/Memory Chatbot.json +2 -2
- langflow/initial_setup/starter_projects/News Aggregator.json +3 -3
- langflow/initial_setup/starter_projects/Nvidia Remix.json +3 -3
- langflow/initial_setup/starter_projects/Pok/303/251dex Agent.json" +1 -1
- langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json +1 -1
- langflow/initial_setup/starter_projects/Price Deal Finder.json +5 -5
- langflow/initial_setup/starter_projects/Research Agent.json +3 -3
- langflow/initial_setup/starter_projects/SaaS Pricing.json +1 -1
- langflow/initial_setup/starter_projects/Search agent.json +1 -1
- langflow/initial_setup/starter_projects/Sequential Tasks Agents.json +7 -7
- langflow/initial_setup/starter_projects/Simple Agent.json +3 -3
- langflow/initial_setup/starter_projects/Social Media Agent.json +1 -1
- langflow/initial_setup/starter_projects/Text Sentiment Analysis.json +1 -1
- langflow/initial_setup/starter_projects/Travel Planning Agents.json +3 -3
- langflow/initial_setup/starter_projects/Vector Store RAG.json +1 -1
- langflow/initial_setup/starter_projects/Youtube Analysis.json +3 -3
- langflow/interface/components.py +23 -22
- langflow/interface/initialize/loading.py +5 -5
- langflow/interface/run.py +1 -1
- langflow/interface/utils.py +1 -1
- langflow/io/__init__.py +0 -1
- langflow/langflow_launcher.py +1 -1
- langflow/load/load.py +2 -7
- langflow/logging/__init__.py +0 -1
- langflow/logging/logger.py +191 -115
- langflow/logging/setup.py +1 -1
- langflow/main.py +37 -52
- langflow/memory.py +7 -7
- langflow/middleware.py +1 -1
- langflow/processing/process.py +3 -3
- langflow/schema/artifact.py +2 -2
- langflow/schema/data.py +10 -2
- langflow/schema/dataframe.py +1 -1
- langflow/schema/message.py +1 -1
- langflow/serialization/serialization.py +1 -1
- langflow/services/auth/utils.py +2 -2
- langflow/services/cache/disk.py +1 -1
- langflow/services/cache/service.py +3 -3
- langflow/services/database/models/flow/model.py +2 -7
- langflow/services/database/models/transactions/crud.py +2 -2
- langflow/services/database/models/user/crud.py +2 -2
- langflow/services/database/service.py +8 -8
- langflow/services/database/utils.py +6 -5
- langflow/services/deps.py +2 -3
- langflow/services/factory.py +1 -1
- langflow/services/flow/flow_runner.py +7 -12
- langflow/services/job_queue/service.py +16 -15
- langflow/services/manager.py +3 -4
- langflow/services/settings/auth.py +1 -1
- langflow/services/settings/base.py +3 -8
- langflow/services/settings/manager.py +1 -1
- langflow/services/settings/utils.py +1 -1
- langflow/services/socket/__init__.py +0 -1
- langflow/services/socket/service.py +3 -3
- langflow/services/socket/utils.py +4 -4
- langflow/services/state/service.py +1 -2
- langflow/services/storage/factory.py +1 -1
- langflow/services/storage/local.py +9 -8
- langflow/services/storage/s3.py +11 -10
- langflow/services/store/service.py +3 -3
- langflow/services/store/utils.py +3 -2
- langflow/services/task/temp_flow_cleanup.py +7 -7
- langflow/services/telemetry/service.py +10 -10
- langflow/services/tracing/arize_phoenix.py +2 -2
- langflow/services/tracing/langfuse.py +1 -1
- langflow/services/tracing/langsmith.py +1 -1
- langflow/services/tracing/langwatch.py +1 -1
- langflow/services/tracing/opik.py +1 -1
- langflow/services/tracing/service.py +25 -6
- langflow/services/tracing/traceloop.py +245 -0
- langflow/services/utils.py +7 -7
- langflow/services/variable/kubernetes.py +3 -3
- langflow/services/variable/kubernetes_secrets.py +2 -1
- langflow/services/variable/service.py +5 -5
- langflow/utils/component_utils.py +9 -6
- langflow/utils/util.py +5 -5
- langflow/utils/validate.py +3 -3
- langflow/utils/voice_utils.py +2 -2
- {langflow_base_nightly-0.5.0.dev37.dist-info → langflow_base_nightly-0.5.0.dev38.dist-info}/METADATA +2 -1
- {langflow_base_nightly-0.5.0.dev37.dist-info → langflow_base_nightly-0.5.0.dev38.dist-info}/RECORD +334 -333
- langflow/frontend/assets/lazyIconImports-t6wEndt1.js +0 -2
- {langflow_base_nightly-0.5.0.dev37.dist-info → langflow_base_nightly-0.5.0.dev38.dist-info}/WHEEL +0 -0
- {langflow_base_nightly-0.5.0.dev37.dist-info → langflow_base_nightly-0.5.0.dev38.dist-info}/entry_points.txt +0 -0
langflow/logging/logger.py
CHANGED
|
@@ -1,33 +1,43 @@
|
|
|
1
|
+
"""Logging configuration for Langflow using structlog."""
|
|
2
|
+
|
|
1
3
|
import json
|
|
2
4
|
import logging
|
|
5
|
+
import logging.handlers
|
|
3
6
|
import os
|
|
4
7
|
import sys
|
|
5
8
|
from collections import deque
|
|
9
|
+
from datetime import datetime
|
|
6
10
|
from pathlib import Path
|
|
7
11
|
from threading import Lock, Semaphore
|
|
8
|
-
from typing import TypedDict
|
|
12
|
+
from typing import Any, TypedDict
|
|
9
13
|
|
|
10
14
|
import orjson
|
|
11
|
-
|
|
15
|
+
import structlog
|
|
12
16
|
from platformdirs import user_cache_dir
|
|
13
|
-
from
|
|
14
|
-
from typing_extensions import NotRequired, override
|
|
17
|
+
from typing_extensions import NotRequired
|
|
15
18
|
|
|
16
19
|
from langflow.settings import DEV
|
|
17
20
|
|
|
18
|
-
VALID_LOG_LEVELS = ["
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
VALID_LOG_LEVELS = ["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"]
|
|
22
|
+
|
|
23
|
+
# Map log level names to integers
|
|
24
|
+
LOG_LEVEL_MAP = {
|
|
25
|
+
"DEBUG": logging.DEBUG,
|
|
26
|
+
"INFO": logging.INFO,
|
|
27
|
+
"WARNING": logging.WARNING,
|
|
28
|
+
"ERROR": logging.ERROR,
|
|
29
|
+
"CRITICAL": logging.CRITICAL,
|
|
30
|
+
}
|
|
23
31
|
|
|
24
32
|
|
|
25
33
|
class SizedLogBuffer:
|
|
34
|
+
"""A buffer for storing log messages for the log retrieval API."""
|
|
35
|
+
|
|
26
36
|
def __init__(
|
|
27
37
|
self,
|
|
28
38
|
max_readers: int = 20, # max number of concurrent readers for the buffer
|
|
29
39
|
):
|
|
30
|
-
"""
|
|
40
|
+
"""Initialize the buffer.
|
|
31
41
|
|
|
32
42
|
The buffer can be overwritten by an env variable LANGFLOW_LOG_RETRIEVER_BUFFER_SIZE
|
|
33
43
|
because the logger is initialized before the settings_service are loaded.
|
|
@@ -40,12 +50,28 @@ class SizedLogBuffer:
|
|
|
40
50
|
self._max = 0
|
|
41
51
|
|
|
42
52
|
def get_write_lock(self) -> Lock:
|
|
53
|
+
"""Get the write lock."""
|
|
43
54
|
return self._wlock
|
|
44
55
|
|
|
45
56
|
def write(self, message: str) -> None:
|
|
57
|
+
"""Write a message to the buffer."""
|
|
46
58
|
record = json.loads(message)
|
|
47
|
-
log_entry = record
|
|
48
|
-
|
|
59
|
+
log_entry = record.get("event", record.get("msg", record.get("text", "")))
|
|
60
|
+
|
|
61
|
+
# Extract timestamp - support both direct timestamp and nested record.time.timestamp
|
|
62
|
+
timestamp = record.get("timestamp", 0)
|
|
63
|
+
if timestamp == 0 and "record" in record:
|
|
64
|
+
# Support nested structure from tests: record.time.timestamp
|
|
65
|
+
time_info = record["record"].get("time", {})
|
|
66
|
+
timestamp = time_info.get("timestamp", 0)
|
|
67
|
+
|
|
68
|
+
if isinstance(timestamp, str):
|
|
69
|
+
# Parse ISO format timestamp
|
|
70
|
+
dt = datetime.fromisoformat(timestamp.replace("Z", "+00:00"))
|
|
71
|
+
epoch = int(dt.timestamp() * 1000)
|
|
72
|
+
else:
|
|
73
|
+
epoch = int(timestamp * 1000)
|
|
74
|
+
|
|
49
75
|
with self._wlock:
|
|
50
76
|
if len(self.buffer) >= self.max:
|
|
51
77
|
for _ in range(len(self.buffer) - self.max + 1):
|
|
@@ -53,9 +79,11 @@ class SizedLogBuffer:
|
|
|
53
79
|
self.buffer.append((epoch, log_entry))
|
|
54
80
|
|
|
55
81
|
def __len__(self) -> int:
|
|
82
|
+
"""Get the length of the buffer."""
|
|
56
83
|
return len(self.buffer)
|
|
57
84
|
|
|
58
85
|
def get_after_timestamp(self, timestamp: int, lines: int = 5) -> dict[int, str]:
|
|
86
|
+
"""Get log entries after a timestamp."""
|
|
59
87
|
rc = {}
|
|
60
88
|
|
|
61
89
|
self._rsemaphore.acquire()
|
|
@@ -73,6 +101,7 @@ class SizedLogBuffer:
|
|
|
73
101
|
return rc
|
|
74
102
|
|
|
75
103
|
def get_before_timestamp(self, timestamp: int, lines: int = 5) -> dict[int, str]:
|
|
104
|
+
"""Get log entries before a timestamp."""
|
|
76
105
|
self._rsemaphore.acquire()
|
|
77
106
|
try:
|
|
78
107
|
with self._wlock:
|
|
@@ -94,6 +123,7 @@ class SizedLogBuffer:
|
|
|
94
123
|
self._rsemaphore.release()
|
|
95
124
|
|
|
96
125
|
def get_last_n(self, last_idx: int) -> dict[int, str]:
|
|
126
|
+
"""Get the last n log entries."""
|
|
97
127
|
self._rsemaphore.acquire()
|
|
98
128
|
try:
|
|
99
129
|
with self._wlock:
|
|
@@ -104,6 +134,7 @@ class SizedLogBuffer:
|
|
|
104
134
|
|
|
105
135
|
@property
|
|
106
136
|
def max(self) -> int:
|
|
137
|
+
"""Get the maximum buffer size."""
|
|
107
138
|
# Get it dynamically to allow for env variable changes
|
|
108
139
|
if self._max == 0:
|
|
109
140
|
env_buffer_size = os.getenv("LANGFLOW_LOG_RETRIEVER_BUFFER_SIZE", "0")
|
|
@@ -113,12 +144,15 @@ class SizedLogBuffer:
|
|
|
113
144
|
|
|
114
145
|
@max.setter
|
|
115
146
|
def max(self, value: int) -> None:
|
|
147
|
+
"""Set the maximum buffer size."""
|
|
116
148
|
self._max = value
|
|
117
149
|
|
|
118
150
|
def enabled(self) -> bool:
|
|
151
|
+
"""Check if the buffer is enabled."""
|
|
119
152
|
return self.max > 0
|
|
120
153
|
|
|
121
154
|
def max_size(self) -> int:
|
|
155
|
+
"""Get the maximum buffer size."""
|
|
122
156
|
return self.max
|
|
123
157
|
|
|
124
158
|
|
|
@@ -126,23 +160,39 @@ class SizedLogBuffer:
|
|
|
126
160
|
log_buffer = SizedLogBuffer()
|
|
127
161
|
|
|
128
162
|
|
|
129
|
-
def
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
163
|
+
def add_serialized(_logger: Any, _method_name: str, event_dict: dict[str, Any]) -> dict[str, Any]:
|
|
164
|
+
"""Add serialized version of the log entry."""
|
|
165
|
+
# Only add serialized if we're in JSON mode (for log buffer)
|
|
166
|
+
if log_buffer.enabled():
|
|
167
|
+
subset = {
|
|
168
|
+
"timestamp": event_dict.get("timestamp", 0),
|
|
169
|
+
"message": event_dict.get("event", ""),
|
|
170
|
+
"level": _method_name.upper(),
|
|
171
|
+
"module": event_dict.get("module", ""),
|
|
172
|
+
}
|
|
173
|
+
event_dict["serialized"] = orjson.dumps(subset)
|
|
174
|
+
return event_dict
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def remove_exception_in_production(_logger: Any, _method_name: str, event_dict: dict[str, Any]) -> dict[str, Any]:
|
|
178
|
+
"""Remove exception details in production."""
|
|
179
|
+
if DEV is False:
|
|
180
|
+
event_dict.pop("exception", None)
|
|
181
|
+
event_dict.pop("exc_info", None)
|
|
182
|
+
return event_dict
|
|
137
183
|
|
|
138
184
|
|
|
139
|
-
def
|
|
140
|
-
|
|
141
|
-
if
|
|
142
|
-
|
|
185
|
+
def buffer_writer(_logger: Any, _method_name: str, event_dict: dict[str, Any]) -> dict[str, Any]:
|
|
186
|
+
"""Write to log buffer if enabled."""
|
|
187
|
+
if log_buffer.enabled():
|
|
188
|
+
# Create a JSON representation for the buffer
|
|
189
|
+
log_buffer.write(json.dumps(event_dict))
|
|
190
|
+
return event_dict
|
|
143
191
|
|
|
144
192
|
|
|
145
193
|
class LogConfig(TypedDict):
|
|
194
|
+
"""Configuration for logging."""
|
|
195
|
+
|
|
146
196
|
log_level: NotRequired[str]
|
|
147
197
|
log_file: NotRequired[Path]
|
|
148
198
|
disable: NotRequired[bool]
|
|
@@ -150,30 +200,6 @@ class LogConfig(TypedDict):
|
|
|
150
200
|
log_format: NotRequired[str]
|
|
151
201
|
|
|
152
202
|
|
|
153
|
-
def is_valid_log_format(format_string) -> bool:
|
|
154
|
-
"""Validates a logging format string by attempting to format it with a dummy LogRecord.
|
|
155
|
-
|
|
156
|
-
Args:
|
|
157
|
-
format_string (str): The format string to validate.
|
|
158
|
-
|
|
159
|
-
Returns:
|
|
160
|
-
bool: True if the format string is valid, False otherwise.
|
|
161
|
-
"""
|
|
162
|
-
record = logging.LogRecord(
|
|
163
|
-
name="dummy", level=logging.INFO, pathname="dummy_path", lineno=0, msg="dummy message", args=None, exc_info=None
|
|
164
|
-
)
|
|
165
|
-
|
|
166
|
-
formatter = logging.Formatter(format_string)
|
|
167
|
-
|
|
168
|
-
try:
|
|
169
|
-
# Attempt to format the record
|
|
170
|
-
formatter.format(record)
|
|
171
|
-
except (KeyError, ValueError, TypeError):
|
|
172
|
-
logger.error("Invalid log format string passed, fallback to default")
|
|
173
|
-
return False
|
|
174
|
-
return True
|
|
175
|
-
|
|
176
|
-
|
|
177
203
|
def configure(
|
|
178
204
|
*,
|
|
179
205
|
log_level: str | None = None,
|
|
@@ -181,11 +207,9 @@ def configure(
|
|
|
181
207
|
disable: bool | None = False,
|
|
182
208
|
log_env: str | None = None,
|
|
183
209
|
log_format: str | None = None,
|
|
184
|
-
async_file: bool = False,
|
|
185
210
|
log_rotation: str | None = None,
|
|
186
211
|
) -> None:
|
|
187
|
-
|
|
188
|
-
logger.disable("langflow")
|
|
212
|
+
"""Configure the logger."""
|
|
189
213
|
if os.getenv("LANGFLOW_LOG_LEVEL", "").upper() in VALID_LOG_LEVELS and log_level is None:
|
|
190
214
|
log_level = os.getenv("LANGFLOW_LOG_LEVEL")
|
|
191
215
|
if log_level is None:
|
|
@@ -198,96 +222,148 @@ def configure(
|
|
|
198
222
|
if log_env is None:
|
|
199
223
|
log_env = os.getenv("LANGFLOW_LOG_ENV", "")
|
|
200
224
|
|
|
201
|
-
|
|
202
|
-
|
|
225
|
+
# Get log format from env if not provided
|
|
226
|
+
if log_format is None:
|
|
227
|
+
log_format = os.getenv("LANGFLOW_LOG_FORMAT")
|
|
228
|
+
|
|
229
|
+
# Configure processors based on environment
|
|
230
|
+
processors = [
|
|
231
|
+
structlog.contextvars.merge_contextvars,
|
|
232
|
+
structlog.processors.add_log_level,
|
|
233
|
+
structlog.processors.TimeStamper(fmt="iso"),
|
|
234
|
+
add_serialized,
|
|
235
|
+
remove_exception_in_production,
|
|
236
|
+
buffer_writer,
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
# Configure output based on environment
|
|
203
240
|
if log_env.lower() == "container" or log_env.lower() == "container_json":
|
|
204
|
-
|
|
241
|
+
processors.append(structlog.processors.JSONRenderer())
|
|
205
242
|
elif log_env.lower() == "container_csv":
|
|
206
|
-
|
|
243
|
+
processors.append(
|
|
244
|
+
structlog.processors.KeyValueRenderer(
|
|
245
|
+
key_order=["timestamp", "level", "module", "event"], drop_missing=True
|
|
246
|
+
)
|
|
247
|
+
)
|
|
207
248
|
else:
|
|
208
|
-
|
|
209
|
-
log_format = os.getenv("LANGFLOW_LOG_FORMAT")
|
|
210
|
-
|
|
211
|
-
if log_format is None or not is_valid_log_format(log_format):
|
|
212
|
-
log_format = DEFAULT_LOG_FORMAT
|
|
213
|
-
# pretty print to rich stdout development-friendly but poor performance, It's better for debugger.
|
|
214
|
-
# suggest directly print to stdout in production
|
|
249
|
+
# Use rich console for pretty printing based on environment variable
|
|
215
250
|
log_stdout_pretty = os.getenv("LANGFLOW_PRETTY_LOGS", "true").lower() == "true"
|
|
216
251
|
if log_stdout_pretty:
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
"level": log_level.upper(),
|
|
223
|
-
}
|
|
224
|
-
]
|
|
225
|
-
)
|
|
252
|
+
# If custom format is provided, use KeyValueRenderer with custom format
|
|
253
|
+
if log_format:
|
|
254
|
+
processors.append(structlog.processors.KeyValueRenderer())
|
|
255
|
+
else:
|
|
256
|
+
processors.append(structlog.dev.ConsoleRenderer(colors=True))
|
|
226
257
|
else:
|
|
227
|
-
|
|
258
|
+
processors.append(structlog.processors.JSONRenderer())
|
|
259
|
+
|
|
260
|
+
# Get numeric log level
|
|
261
|
+
numeric_level = LOG_LEVEL_MAP.get(log_level.upper(), logging.ERROR)
|
|
262
|
+
|
|
263
|
+
# Configure structlog
|
|
264
|
+
structlog.configure(
|
|
265
|
+
processors=processors,
|
|
266
|
+
wrapper_class=structlog.make_filtering_bound_logger(numeric_level),
|
|
267
|
+
context_class=dict,
|
|
268
|
+
logger_factory=structlog.PrintLoggerFactory(file=sys.stdout)
|
|
269
|
+
if not log_file
|
|
270
|
+
else structlog.stdlib.LoggerFactory(),
|
|
271
|
+
cache_logger_on_first_use=True,
|
|
272
|
+
)
|
|
228
273
|
|
|
229
|
-
|
|
274
|
+
# Set up file logging if needed
|
|
275
|
+
if log_file:
|
|
276
|
+
if not log_file.parent.exists():
|
|
230
277
|
cache_dir = Path(user_cache_dir("langflow"))
|
|
231
|
-
logger.debug(f"Cache directory: {cache_dir}")
|
|
232
278
|
log_file = cache_dir / "langflow.log"
|
|
233
|
-
logger.debug(f"Log file: {log_file}")
|
|
234
279
|
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
280
|
+
# Parse rotation settings
|
|
281
|
+
if log_rotation:
|
|
282
|
+
# Handle rotation like "1 day", "100 MB", etc.
|
|
283
|
+
max_bytes = 10 * 1024 * 1024 # Default 10MB
|
|
284
|
+
if "MB" in log_rotation.upper():
|
|
285
|
+
try:
|
|
286
|
+
# Look for pattern like "100 MB" (with space)
|
|
287
|
+
parts = log_rotation.split()
|
|
288
|
+
expected_parts = 2
|
|
289
|
+
if len(parts) >= expected_parts and parts[1].upper() == "MB":
|
|
290
|
+
mb = int(parts[0])
|
|
291
|
+
if mb > 0: # Only use valid positive values
|
|
292
|
+
max_bytes = mb * 1024 * 1024
|
|
293
|
+
except (ValueError, IndexError):
|
|
294
|
+
pass
|
|
295
|
+
else:
|
|
296
|
+
max_bytes = 10 * 1024 * 1024 # Default 10MB
|
|
251
297
|
|
|
252
|
-
|
|
253
|
-
|
|
298
|
+
# Since structlog doesn't have built-in rotation, we'll use stdlib logging for file output
|
|
299
|
+
file_handler = logging.handlers.RotatingFileHandler(
|
|
300
|
+
log_file,
|
|
301
|
+
maxBytes=max_bytes,
|
|
302
|
+
backupCount=5,
|
|
303
|
+
)
|
|
304
|
+
file_handler.setFormatter(logging.Formatter("%(message)s"))
|
|
254
305
|
|
|
255
|
-
|
|
306
|
+
# Add file handler to root logger
|
|
307
|
+
logging.root.addHandler(file_handler)
|
|
308
|
+
logging.root.setLevel(numeric_level)
|
|
256
309
|
|
|
310
|
+
# Set up interceptors for uvicorn and gunicorn
|
|
257
311
|
setup_uvicorn_logger()
|
|
258
312
|
setup_gunicorn_logger()
|
|
259
313
|
|
|
314
|
+
# Create the global logger instance
|
|
315
|
+
global logger # noqa: PLW0603
|
|
316
|
+
logger = structlog.get_logger()
|
|
317
|
+
|
|
318
|
+
if disable:
|
|
319
|
+
# In structlog, we can set a very high filter level to effectively disable logging
|
|
320
|
+
structlog.configure(
|
|
321
|
+
wrapper_class=structlog.make_filtering_bound_logger(logging.CRITICAL),
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
logger.debug("Logger set up with log level: %s", log_level)
|
|
325
|
+
|
|
260
326
|
|
|
261
327
|
def setup_uvicorn_logger() -> None:
|
|
328
|
+
"""Redirect uvicorn logs through structlog."""
|
|
262
329
|
loggers = (logging.getLogger(name) for name in logging.root.manager.loggerDict if name.startswith("uvicorn."))
|
|
263
330
|
for uvicorn_logger in loggers:
|
|
264
331
|
uvicorn_logger.handlers = []
|
|
265
|
-
|
|
332
|
+
uvicorn_logger.propagate = True
|
|
266
333
|
|
|
267
334
|
|
|
268
335
|
def setup_gunicorn_logger() -> None:
|
|
269
|
-
|
|
270
|
-
logging.getLogger("gunicorn.
|
|
336
|
+
"""Redirect gunicorn logs through structlog."""
|
|
337
|
+
logging.getLogger("gunicorn.error").handlers = []
|
|
338
|
+
logging.getLogger("gunicorn.error").propagate = True
|
|
339
|
+
logging.getLogger("gunicorn.access").handlers = []
|
|
340
|
+
logging.getLogger("gunicorn.access").propagate = True
|
|
271
341
|
|
|
272
342
|
|
|
273
343
|
class InterceptHandler(logging.Handler):
|
|
274
|
-
"""
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
344
|
+
"""Intercept standard logging messages and route them to structlog."""
|
|
345
|
+
|
|
346
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
347
|
+
"""Emit a log record by passing it to structlog."""
|
|
348
|
+
# Get corresponding structlog logger
|
|
349
|
+
logger_name = record.name
|
|
350
|
+
structlog_logger = structlog.get_logger(logger_name)
|
|
351
|
+
|
|
352
|
+
# Map log levels
|
|
353
|
+
level = record.levelno
|
|
354
|
+
if level >= logging.CRITICAL:
|
|
355
|
+
structlog_logger.critical(record.getMessage())
|
|
356
|
+
elif level >= logging.ERROR:
|
|
357
|
+
structlog_logger.error(record.getMessage())
|
|
358
|
+
elif level >= logging.WARNING:
|
|
359
|
+
structlog_logger.warning(record.getMessage())
|
|
360
|
+
elif level >= logging.INFO:
|
|
361
|
+
structlog_logger.info(record.getMessage())
|
|
362
|
+
else:
|
|
363
|
+
structlog_logger.debug(record.getMessage())
|
|
286
364
|
|
|
287
|
-
# Find caller from where originated the logged message
|
|
288
|
-
frame, depth = logging.currentframe(), 2
|
|
289
|
-
while frame.f_code.co_filename == logging.__file__ and frame.f_back:
|
|
290
|
-
frame = frame.f_back
|
|
291
|
-
depth += 1
|
|
292
365
|
|
|
293
|
-
|
|
366
|
+
# Initialize logger - will be reconfigured when configure() is called
|
|
367
|
+
# Set it to critical level
|
|
368
|
+
logger: structlog.BoundLogger = structlog.get_logger()
|
|
369
|
+
configure(log_level="CRITICAL", disable=True)
|
langflow/logging/setup.py
CHANGED