langflow-base-nightly 0.5.0.dev11__py3-none-any.whl → 0.5.0.dev13__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/alembic/versions/3162e83e485f_add_auth_settings_to_folder_and_merge.py +58 -0
- langflow/api/v1/flows.py +11 -1
- langflow/api/v1/mcp_projects.py +30 -9
- langflow/api/v1/schemas.py +36 -0
- langflow/base/models/openai_constants.py +5 -3
- langflow/components/agents/agent.py +61 -4
- langflow/frontend/assets/{SlackIcon-BEQsp2tG.js → SlackIcon-B1waip4k.js} +1 -1
- langflow/frontend/assets/{Wikipedia-CylSh2Rz.js → Wikipedia-C5dnUOP0.js} +1 -1
- langflow/frontend/assets/{Wolfram-BbLCNQCI.js → Wolfram-DhcO0RVc.js} +1 -1
- langflow/frontend/assets/{index-BwWOFcx9.js → index-3biIaEbi.js} +1 -1
- langflow/frontend/assets/{index-fU437Xuh.js → index-418YVFa2.js} +1 -1
- langflow/frontend/assets/{index-CmPIFu12.js → index-606CKdUf.js} +1 -1
- langflow/frontend/assets/{index-D6qchtKo.js → index-8DyHY_Bk.js} +1 -1
- langflow/frontend/assets/{index-DtjOwLQC.js → index-9TR2hnD_.js} +1 -1
- langflow/frontend/assets/{index-Buf0FLlA.js → index-B5ZG67DK.js} +1 -1
- langflow/frontend/assets/{index-DvZ2dP1K.js → index-B6e8DnbV.js} +1 -1
- langflow/frontend/assets/{index-5ls6VK_c.js → index-BBGrtgHW.js} +1 -1
- langflow/frontend/assets/{index-C2fMifvM.js → index-BC8MvYGc.js} +1 -1
- langflow/frontend/assets/{index-DgghztJk.js → index-BCSQ18YB.js} +1 -1
- langflow/frontend/assets/{index-DXMYOwee.js → index-BC_ZSBd8.js} +1 -1
- langflow/frontend/assets/{index-BDASu5_h.js → index-BGoj1qt5.js} +1 -1
- langflow/frontend/assets/{index-BnRJS1jE.js → index-BHZEUpSJ.js} +1 -1
- langflow/frontend/assets/{index-Cqc93Aww.js → index-BMXOUkQC.js} +1 -1
- langflow/frontend/assets/{index-CoAX4KHA.js → index-BONWErnQ.js} +1 -1
- langflow/frontend/assets/{index-ArQPJTY-.js → index-BSw4Njsa.js} +1 -1
- langflow/frontend/assets/{index-cOLi_68F.js → index-BTgluuBN.js} +1 -1
- langflow/frontend/assets/{index-B7gZiD-W.js → index-BU-Bn5mu.js} +1 -1
- langflow/frontend/assets/{index-DeMmL8Mo.js → index-BYlJ6oLH.js} +1 -1
- langflow/frontend/assets/{index-DLoNvjqt.js → index-Bbl1tT9J.js} +1 -1
- langflow/frontend/assets/{index-DjNRiQay.js → index-Bf5rmL-A.js} +1 -1
- langflow/frontend/assets/{index-ZPrp_qyL.js → index-BfeYY-C1.js} +1 -1
- langflow/frontend/assets/{index-DzFPLySG.js → index-BlMOr3_J.js} +1 -1
- langflow/frontend/assets/{index-uxytSC6u.js → index-Bn6oRo0n.js} +1 -1
- langflow/frontend/assets/{index-Yrff3uIT.js → index-BrG-lJ13.js} +1 -1
- langflow/frontend/assets/{index-BjcscQOG.js → index-Bt6nxewq.js} +1 -1
- langflow/frontend/assets/{index-CSe6UjxV.js → index-BwVK35FL.js} +1 -1
- langflow/frontend/assets/{index-GF2LJgkR.js → index-C-s9qpIS.js} +1 -1
- langflow/frontend/assets/{index-CDDBjrKl.js → index-C0HZtOht.js} +1 -1
- langflow/frontend/assets/{index-DmZZmu5_.js → index-C3HQLjdj.js} +1 -1
- langflow/frontend/assets/{index-Q0Ex46_F.js → index-C5kZL0cq.js} +1 -1
- langflow/frontend/assets/{index-DFckK5jC.js → index-C7_J2NrZ.js} +1 -1
- langflow/frontend/assets/{index-Bxa7Zqaq.js → index-CALzRXXv.js} +1 -1
- langflow/frontend/assets/{index-_AhGSFEp.js → index-CBUjLnxi.js} +1 -1
- langflow/frontend/assets/{index-D6iJ0ixS.js → index-CCIWuZBs.js} +1 -1
- langflow/frontend/assets/{index-H15pIDqA.js → index-CDEm9KAj.js} +1 -1
- langflow/frontend/assets/{index-Dgd8GGgG.js → index-CDSjGlZV.js} +1 -1
- langflow/frontend/assets/{index-BxPGc9G_.js → index-CDbyKwTG.js} +1 -1
- langflow/frontend/assets/{index-Vx9vra5E.js → index-CDpU78JK.js} +1 -1
- langflow/frontend/assets/{index-HbhXQ4iI.js → index-CDuvFcaF.js} +1 -1
- langflow/frontend/assets/{index-Bki1gbZ4.js → index-CKPKfZJn.js} +1 -1
- langflow/frontend/assets/{index-DaosAMPL.js → index-CLbIIEk2.js} +1 -1
- langflow/frontend/assets/{index-C9ZDIZFW.js → index-CPg6geGH.js} +1 -1
- langflow/frontend/assets/{index-pwj4p8sb.js → index-CRjDABKd.js} +1 -1
- langflow/frontend/assets/{index-B61eUMTR.js → index-CViOvTFf.js} +1 -1
- langflow/frontend/assets/{index-lJ1V4apH.js → index-CXUUEanr.js} +1 -1
- langflow/frontend/assets/{index-Dj6hJobz.js → index-C_euB6Gl.js} +1 -1
- langflow/frontend/assets/{index-BlSZbUqf.js → index-Casu8D9q.js} +1 -1
- langflow/frontend/assets/{index-p77FDSRr.js → index-Cg4VEh3c.js} +1 -1
- langflow/frontend/assets/{index-O3c1ky7v.js → index-CgIcVOr8.js} +1 -1
- langflow/frontend/assets/{index-CEau7eX7.js → index-Cg_tVm4-.js} +1 -1
- langflow/frontend/assets/{index-CmSCL35l.js → index-ChqaoD3t.js} +1 -1
- langflow/frontend/assets/{index-CdaKd40h.js → index-Cm0S83En.js} +1 -1
- langflow/frontend/assets/{index-DEwfBIGT.js → index-CmGwOqUn.js} +1 -1
- langflow/frontend/assets/{index-CBOYVi1U.js → index-CsndNop1.js} +1 -1
- langflow/frontend/assets/{index-BymhxBmN.js → index-D3JSU9T-.js} +1 -1
- langflow/frontend/assets/{index-CDN9FxX3.js → index-D3dEuwpy.js} +1 -1
- langflow/frontend/assets/index-D4GoWOiL.css +1 -0
- langflow/frontend/assets/{index-KcUnsxlf.js → index-D6ea_8pm.js} +1 -1
- langflow/frontend/assets/{index-CJ5EUvrn.js → index-D7Zt_u8q.js} +1 -1
- langflow/frontend/assets/{index-BCodFIaO.js → index-D9hSZOYT.js} +1 -1
- langflow/frontend/assets/{index-BorUWqkM.js → index-DB7TCTGT.js} +1 -1
- langflow/frontend/assets/{index-BRLJm4Du.js → index-DBmHwu6w.js} +1 -1
- langflow/frontend/assets/{index-Br2kJx5F.js → index-DCetRusr.js} +1 -1
- langflow/frontend/assets/{index-BSZfrTzR.js → index-DFTYUoaZ.js} +1 -1
- langflow/frontend/assets/{index-DufevlPT.js → index-DFiKJBMw.js} +1 -1
- langflow/frontend/assets/{index-B5S9h8ok.js → index-DH7xKo5T.js} +1 -1
- langflow/frontend/assets/{index-DKho7fub.js → index-DKVaEmO7.js} +1 -1
- langflow/frontend/assets/{index-BsVHbutF.js → index-DM_Uy5wE.js} +1 -1
- langflow/frontend/assets/{index-TUSpXwVe.js → index-DMumbC9j.js} +1 -1
- langflow/frontend/assets/{index-D_AWHRfe.js → index-DOD107en.js} +1 -1
- langflow/frontend/assets/{index-DNOP-INQ.js → index-DOW9ZSLB.js} +1 -1
- langflow/frontend/assets/{index-CogD177T.js → index-DQHDRmym.js} +1 -1
- langflow/frontend/assets/{index-D8nmnanz.js → index-DUE44GEX.js} +1 -1
- langflow/frontend/assets/{index-k9UFhzxg.js → index-DYrXxgrb.js} +1 -1
- langflow/frontend/assets/{index-CdPp99Ov.js → index-DYv6Aras.js} +1 -1
- langflow/frontend/assets/{index-gsz-bhOF.js → index-DZgXMtLr.js} +1 -1
- langflow/frontend/assets/{index-DpMb4SyP.js → index-Dcalb9GV.js} +1 -1
- langflow/frontend/assets/{index-B2VOPfSQ.js → index-DgAnAkZI.js} +1 -1
- langflow/frontend/assets/{index-C3Bj4_FP.js → index-Dh4QIx-9.js} +1 -1
- langflow/frontend/assets/{index-DJzLRh66.js → index-DiC6aHWh.js} +1 -1
- langflow/frontend/assets/{index-C9dL6qYU.js → index-DjQo2TKu.js} +1 -1
- langflow/frontend/assets/{index-ChyV4bY1.js → index-Dm2EC55c.js} +1 -1
- langflow/frontend/assets/{index-YXNg_MqK.js → index-Dn6DEQeW.js} +1 -1
- langflow/frontend/assets/{index-D2K8Dxca.js → index-DpVlWsbf.js} +1 -1
- langflow/frontend/assets/{index-UVKuDcRW.js → index-DpxIP5eR.js} +1 -1
- langflow/frontend/assets/{index-Bhm1dylP.js → index-DtNmksPw.js} +1 -1
- langflow/frontend/assets/{index-lp0TR1VG.js → index-DvZa-h7F.js} +1 -1
- langflow/frontend/assets/{index-DcTv_MVV.js → index-DvfpMNxC.js} +1 -1
- langflow/frontend/assets/{index-BtXZCxsi.js → index-DwSpFzJE.js} +1 -1
- langflow/frontend/assets/{index-CBGa-ML1.js → index-Dxt2wnqB.js} +1 -1
- langflow/frontend/assets/{index-DYwMDNLL.js → index-Dym17axM.js} +1 -1
- langflow/frontend/assets/{index-C9KrGJ67.js → index-FRFezpnl.js} +1 -1
- langflow/frontend/assets/{index-dg4h4aV9.js → index-JXRrBiMq.js} +1 -1
- langflow/frontend/assets/{index-DZ4RRuo1.js → index-JnJLq8vw.js} +1 -1
- langflow/frontend/assets/{index-DysqOh2v.js → index-Lj5U_BEs.js} +1 -1
- langflow/frontend/assets/{index-ChPNbgSb.js → index-MzhQqWgp.js} +1 -1
- langflow/frontend/assets/{index-CtzhOjCJ.js → index-Nrq24q0b.js} +1 -1
- langflow/frontend/assets/{index-Dgtl-Ryc.js → index-PR9CDiB2.js} +1 -1
- langflow/frontend/assets/{index-kjgyrJKk.js → index-Ps_-SFhI.js} +1 -1
- langflow/frontend/assets/{index-DyIpqQ6u.js → index-QtS6b7Sw.js} +1 -1
- langflow/frontend/assets/{index-D38ii1eC.js → index-SG4iMGMH.js} +1 -1
- langflow/frontend/assets/{index-C_H9PvPC.js → index-VgSSRzOC.js} +1 -1
- langflow/frontend/assets/{index-CbN90tiv.js → index-VroAkSXX.js} +1 -1
- langflow/frontend/assets/{index-DCNa4h3y.js → index-XRYx-9PH.js} +1 -1
- langflow/frontend/assets/{index-DGV6oDTb.js → index-X_N2VjCI.js} +1 -1
- langflow/frontend/assets/{index-Bpv14pFu.js → index-ZEtb94y9.js} +1 -1
- langflow/frontend/assets/{index-ZHQE-way.js → index-ZdUecE-Q.js} +1 -1
- langflow/frontend/assets/{index-CcS86fAH.js → index-eGM7b_zA.js} +1 -1
- langflow/frontend/assets/{index-N3NiikE-.js → index-ewyyoy2D.js} +1 -1
- langflow/frontend/assets/{index-GUM5ctOD.js → index-gY4GknXS.js} +1 -1
- langflow/frontend/assets/{index-BTPSO7Ty.js → index-gm2XOLA2.js} +1 -1
- langflow/frontend/assets/{index--afKjQV4.js → index-ipP5SzLr.js} +1 -1
- langflow/frontend/assets/{index-BUepyNwR.js → index-is0kQpz3.js} +1 -1
- langflow/frontend/assets/{index-DiYhK7Hs.js → index-kElqCHmt.js} +1 -1
- langflow/frontend/assets/{index-DYj_t4sx.js → index-kQTNfH4u.js} +1 -1
- langflow/frontend/assets/{index-gnvplQfi.js → index-m4Hpi_aX.js} +1 -1
- langflow/frontend/assets/{index-DOZ4j-co.js → index-nLSeiMV2.js} +1 -1
- langflow/frontend/assets/{index-B1yGg3ui.js → index-rDnX1gJr.js} +1907 -1907
- langflow/frontend/assets/{index-CTIjE6ec.js → index-zO8eyFDr.js} +1 -1
- langflow/frontend/assets/lazyIconImports-GHEHdmsf.js +2 -0
- langflow/frontend/assets/{use-post-add-user-CNxc7cHz.js → use-post-add-user-BanYOJbs.js} +1 -1
- langflow/frontend/index.html +2 -2
- langflow/initial_setup/starter_projects/Instagram Copywriter.json +147 -100
- langflow/initial_setup/starter_projects/Invoice Summarizer.json +1 -1
- langflow/initial_setup/starter_projects/Market Research.json +1 -1
- langflow/initial_setup/starter_projects/News Aggregator.json +1 -1
- langflow/initial_setup/starter_projects/Nvidia Remix.json +1 -1
- langflow/initial_setup/starter_projects/Pok/303/251dex Agent.json" +1 -1
- langflow/initial_setup/starter_projects/Price Deal Finder.json +1 -1
- langflow/initial_setup/starter_projects/Research Agent.json +1 -1
- 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 +3 -3
- langflow/initial_setup/starter_projects/Simple Agent.json +1 -1
- langflow/initial_setup/starter_projects/Social Media Agent.json +1 -1
- langflow/initial_setup/starter_projects/Travel Planning Agents.json +3 -3
- langflow/initial_setup/starter_projects/Youtube Analysis.json +1 -1
- langflow/services/database/models/folder/model.py +7 -1
- langflow/services/settings/feature_flags.py +1 -0
- {langflow_base_nightly-0.5.0.dev11.dist-info → langflow_base_nightly-0.5.0.dev13.dist-info}/METADATA +1 -1
- {langflow_base_nightly-0.5.0.dev11.dist-info → langflow_base_nightly-0.5.0.dev13.dist-info}/RECORD +153 -152
- langflow/frontend/assets/index-MB8UM6Ob.css +0 -1
- langflow/frontend/assets/lazyIconImports-B2rERpGa.js +0 -2
- {langflow_base_nightly-0.5.0.dev11.dist-info → langflow_base_nightly-0.5.0.dev13.dist-info}/WHEEL +0 -0
- {langflow_base_nightly-0.5.0.dev11.dist-info → langflow_base_nightly-0.5.0.dev13.dist-info}/entry_points.txt +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"""Add auth_settings column to folder table and merge migration branches.
|
|
2
|
+
|
|
3
|
+
Revision ID: 3162e83e485f
|
|
4
|
+
Revises: 0ae3a2674f32, d9a6ea21edcd
|
|
5
|
+
Create Date: 2025-01-16 13:00:00.000000
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from collections.abc import Sequence
|
|
10
|
+
|
|
11
|
+
import sqlalchemy as sa
|
|
12
|
+
from alembic import op
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = "3162e83e485f"
|
|
16
|
+
down_revision: str | Sequence[str] | None = ("0ae3a2674f32", "d9a6ea21edcd")
|
|
17
|
+
branch_labels: str | Sequence[str] | None = None
|
|
18
|
+
depends_on: str | Sequence[str] | None = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
"""Add auth_settings column to folder table and merge migration branches."""
|
|
23
|
+
conn = op.get_bind()
|
|
24
|
+
inspector = sa.inspect(conn)
|
|
25
|
+
|
|
26
|
+
# Check if folder table exists
|
|
27
|
+
table_names = inspector.get_table_names()
|
|
28
|
+
if "folder" not in table_names:
|
|
29
|
+
# If folder table doesn't exist, skip this migration
|
|
30
|
+
return
|
|
31
|
+
|
|
32
|
+
# Get current column names in folder table
|
|
33
|
+
column_names = [column["name"] for column in inspector.get_columns("folder")]
|
|
34
|
+
|
|
35
|
+
# Add auth_settings column to folder table if it doesn't exist
|
|
36
|
+
with op.batch_alter_table("folder", schema=None) as batch_op:
|
|
37
|
+
if "auth_settings" not in column_names:
|
|
38
|
+
batch_op.add_column(sa.Column("auth_settings", sa.JSON(), nullable=True))
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def downgrade() -> None:
|
|
42
|
+
"""Remove auth_settings column from folder table."""
|
|
43
|
+
conn = op.get_bind()
|
|
44
|
+
inspector = sa.inspect(conn)
|
|
45
|
+
|
|
46
|
+
# Check if folder table exists
|
|
47
|
+
table_names = inspector.get_table_names()
|
|
48
|
+
if "folder" not in table_names:
|
|
49
|
+
# If folder table doesn't exist, skip this migration
|
|
50
|
+
return
|
|
51
|
+
|
|
52
|
+
# Get current column names in folder table
|
|
53
|
+
column_names = [column["name"] for column in inspector.get_columns("folder")]
|
|
54
|
+
|
|
55
|
+
# Remove auth_settings column from folder table if it exists
|
|
56
|
+
with op.batch_alter_table("folder", schema=None) as batch_op:
|
|
57
|
+
if "auth_settings" in column_names:
|
|
58
|
+
batch_op.drop_column("auth_settings")
|
langflow/api/v1/flows.py
CHANGED
|
@@ -83,7 +83,15 @@ async def _new_flow(
|
|
|
83
83
|
)
|
|
84
84
|
).all()
|
|
85
85
|
if flows:
|
|
86
|
-
|
|
86
|
+
# Use regex to extract numbers only from flows that follow the copy naming pattern:
|
|
87
|
+
# "{original_name} ({number})"
|
|
88
|
+
# This avoids extracting numbers from the original flow name if it naturally contains parentheses
|
|
89
|
+
#
|
|
90
|
+
# Examples:
|
|
91
|
+
# - For flow "My Flow": matches "My Flow (1)", "My Flow (2)" → extracts 1, 2
|
|
92
|
+
# - For flow "Analytics (Q1)": matches "Analytics (Q1) (1)" → extracts 1
|
|
93
|
+
# but does NOT match "Analytics (Q1)" → avoids extracting the original "1"
|
|
94
|
+
extract_number = re.compile(rf"^{re.escape(flow.name)} \((\d+)\)$")
|
|
87
95
|
numbers = []
|
|
88
96
|
for _flow in flows:
|
|
89
97
|
result = extract_number.search(_flow.name)
|
|
@@ -91,6 +99,8 @@ async def _new_flow(
|
|
|
91
99
|
numbers.append(int(result.groups(1)[0]))
|
|
92
100
|
if numbers:
|
|
93
101
|
flow.name = f"{flow.name} ({max(numbers) + 1})"
|
|
102
|
+
else:
|
|
103
|
+
flow.name = f"{flow.name} (1)"
|
|
94
104
|
else:
|
|
95
105
|
flow.name = f"{flow.name} (1)"
|
|
96
106
|
# Now check if the endpoint is unique
|
langflow/api/v1/mcp_projects.py
CHANGED
|
@@ -29,11 +29,17 @@ from langflow.api.v1.mcp_utils import (
|
|
|
29
29
|
handle_mcp_errors,
|
|
30
30
|
handle_read_resource,
|
|
31
31
|
)
|
|
32
|
-
from langflow.api.v1.schemas import
|
|
32
|
+
from langflow.api.v1.schemas import (
|
|
33
|
+
MCPInstallRequest,
|
|
34
|
+
MCPProjectResponse,
|
|
35
|
+
MCPProjectUpdateRequest,
|
|
36
|
+
MCPSettings,
|
|
37
|
+
)
|
|
33
38
|
from langflow.base.mcp.constants import MAX_MCP_SERVER_NAME_LENGTH
|
|
34
39
|
from langflow.base.mcp.util import sanitize_mcp_name
|
|
35
40
|
from langflow.services.database.models import Flow, Folder
|
|
36
41
|
from langflow.services.deps import get_settings_service, session_scope
|
|
42
|
+
from langflow.services.settings.feature_flags import FEATURE_FLAGS
|
|
37
43
|
|
|
38
44
|
logger = logging.getLogger(__name__)
|
|
39
45
|
|
|
@@ -60,7 +66,7 @@ async def list_project_tools(
|
|
|
60
66
|
current_user: CurrentActiveMCPUser,
|
|
61
67
|
*,
|
|
62
68
|
mcp_enabled: bool = True,
|
|
63
|
-
) ->
|
|
69
|
+
) -> MCPProjectResponse:
|
|
64
70
|
"""List all tools in a project that are enabled for MCP."""
|
|
65
71
|
tools: list[MCPSettings] = []
|
|
66
72
|
try:
|
|
@@ -114,12 +120,19 @@ async def list_project_tools(
|
|
|
114
120
|
logger.warning(msg)
|
|
115
121
|
continue
|
|
116
122
|
|
|
123
|
+
# Get project-level auth settings
|
|
124
|
+
auth_settings = None
|
|
125
|
+
if project.auth_settings:
|
|
126
|
+
from langflow.api.v1.schemas import AuthSettings
|
|
127
|
+
|
|
128
|
+
auth_settings = AuthSettings(**project.auth_settings)
|
|
129
|
+
|
|
117
130
|
except Exception as e:
|
|
118
131
|
msg = f"Error listing project tools: {e!s}"
|
|
119
132
|
logger.exception(msg)
|
|
120
133
|
raise HTTPException(status_code=500, detail=str(e)) from e
|
|
121
134
|
|
|
122
|
-
return tools
|
|
135
|
+
return MCPProjectResponse(tools=tools, auth_settings=auth_settings)
|
|
123
136
|
|
|
124
137
|
|
|
125
138
|
@router.head("/{project_id}/sse", response_class=HTMLResponse, include_in_schema=False)
|
|
@@ -218,10 +231,10 @@ async def handle_project_messages_with_slash(project_id: UUID, request: Request,
|
|
|
218
231
|
@router.patch("/{project_id}", status_code=200)
|
|
219
232
|
async def update_project_mcp_settings(
|
|
220
233
|
project_id: UUID,
|
|
221
|
-
|
|
234
|
+
request: MCPProjectUpdateRequest,
|
|
222
235
|
current_user: CurrentActiveMCPUser,
|
|
223
236
|
):
|
|
224
|
-
"""Update the MCP settings of all flows in a project."""
|
|
237
|
+
"""Update the MCP settings of all flows in a project and project-level auth settings."""
|
|
225
238
|
try:
|
|
226
239
|
async with session_scope() as session:
|
|
227
240
|
# Fetch the project first to verify it exists and belongs to the current user
|
|
@@ -236,9 +249,16 @@ async def update_project_mcp_settings(
|
|
|
236
249
|
if not project:
|
|
237
250
|
raise HTTPException(status_code=404, detail="Project not found")
|
|
238
251
|
|
|
252
|
+
# Update project-level auth settings
|
|
253
|
+
if request.auth_settings:
|
|
254
|
+
project.auth_settings = request.auth_settings.model_dump(mode="json")
|
|
255
|
+
else:
|
|
256
|
+
project.auth_settings = None
|
|
257
|
+
session.add(project)
|
|
258
|
+
|
|
239
259
|
# Query flows in the project
|
|
240
260
|
flows = (await session.exec(select(Flow).where(Flow.folder_id == project_id))).all()
|
|
241
|
-
flows_to_update = {x.id: x for x in settings}
|
|
261
|
+
flows_to_update = {x.id: x for x in request.settings}
|
|
242
262
|
|
|
243
263
|
updated_flows = []
|
|
244
264
|
for flow in flows:
|
|
@@ -256,7 +276,7 @@ async def update_project_mcp_settings(
|
|
|
256
276
|
|
|
257
277
|
await session.commit()
|
|
258
278
|
|
|
259
|
-
return {"message": f"Updated MCP settings for {len(updated_flows)} flows"}
|
|
279
|
+
return {"message": f"Updated MCP settings for {len(updated_flows)} flows and project auth settings"}
|
|
260
280
|
|
|
261
281
|
except Exception as e:
|
|
262
282
|
msg = f"Error updating project MCP settings: {e!s}"
|
|
@@ -348,7 +368,8 @@ async def install_mcp_config(
|
|
|
348
368
|
# Determine command and args based on operating system
|
|
349
369
|
os_type = platform.system()
|
|
350
370
|
command = "uvx"
|
|
351
|
-
|
|
371
|
+
mcp_tool = "mcp-composer" if FEATURE_FLAGS.mcp_composer else "mcp-proxy"
|
|
372
|
+
args = [mcp_tool, sse_url]
|
|
352
373
|
|
|
353
374
|
# Check if running on WSL (will appear as Linux but with Microsoft in release info)
|
|
354
375
|
is_wsl = os_type == "Linux" and "microsoft" in platform.uname().release.lower()
|
|
@@ -381,7 +402,7 @@ async def install_mcp_config(
|
|
|
381
402
|
|
|
382
403
|
if os_type == "Windows":
|
|
383
404
|
command = "cmd"
|
|
384
|
-
args = ["/c", "uvx",
|
|
405
|
+
args = ["/c", "uvx", mcp_tool, sse_url]
|
|
385
406
|
logger.debug("Windows detected, using cmd command")
|
|
386
407
|
|
|
387
408
|
name = project.name
|
langflow/api/v1/schemas.py
CHANGED
|
@@ -8,6 +8,7 @@ from pydantic import (
|
|
|
8
8
|
BaseModel,
|
|
9
9
|
ConfigDict,
|
|
10
10
|
Field,
|
|
11
|
+
SecretStr,
|
|
11
12
|
field_serializer,
|
|
12
13
|
field_validator,
|
|
13
14
|
model_serializer,
|
|
@@ -440,6 +441,27 @@ class CancelFlowResponse(BaseModel):
|
|
|
440
441
|
message: str
|
|
441
442
|
|
|
442
443
|
|
|
444
|
+
class AuthSettings(BaseModel):
|
|
445
|
+
"""Model representing authentication settings for MCP."""
|
|
446
|
+
|
|
447
|
+
auth_type: Literal["none", "apikey", "basic", "bearer", "iam", "oauth"] = "none"
|
|
448
|
+
api_key: SecretStr | None = None
|
|
449
|
+
username: str | None = None
|
|
450
|
+
password: SecretStr | None = None
|
|
451
|
+
bearer_token: SecretStr | None = None
|
|
452
|
+
iam_endpoint: str | None = None
|
|
453
|
+
oauth_host: str | None = None
|
|
454
|
+
oauth_port: str | None = None
|
|
455
|
+
oauth_server_url: str | None = None
|
|
456
|
+
oauth_callback_path: str | None = None
|
|
457
|
+
oauth_client_id: str | None = None
|
|
458
|
+
oauth_client_secret: str | None = None
|
|
459
|
+
oauth_auth_url: str | None = None
|
|
460
|
+
oauth_token_url: str | None = None
|
|
461
|
+
oauth_mcp_scope: str | None = None
|
|
462
|
+
oauth_provider_scope: str | None = None
|
|
463
|
+
|
|
464
|
+
|
|
443
465
|
class MCPSettings(BaseModel):
|
|
444
466
|
"""Model representing MCP settings for a flow."""
|
|
445
467
|
|
|
@@ -451,5 +473,19 @@ class MCPSettings(BaseModel):
|
|
|
451
473
|
description: str | None = None
|
|
452
474
|
|
|
453
475
|
|
|
476
|
+
class MCPProjectUpdateRequest(BaseModel):
|
|
477
|
+
"""Request model for updating MCP project settings including auth."""
|
|
478
|
+
|
|
479
|
+
settings: list[MCPSettings]
|
|
480
|
+
auth_settings: AuthSettings | None = None
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
class MCPProjectResponse(BaseModel):
|
|
484
|
+
"""Response model for MCP project tools with auth settings."""
|
|
485
|
+
|
|
486
|
+
tools: list[MCPSettings]
|
|
487
|
+
auth_settings: AuthSettings | None = None
|
|
488
|
+
|
|
489
|
+
|
|
454
490
|
class MCPInstallRequest(BaseModel):
|
|
455
491
|
client: str
|
|
@@ -8,7 +8,9 @@ OPENAI_MODELS_DETAILED = [
|
|
|
8
8
|
create_model_metadata(provider="OpenAI", name="gpt-4.1", icon="OpenAI", tool_calling=True),
|
|
9
9
|
create_model_metadata(provider="OpenAI", name="gpt-4.1-mini", icon="OpenAI", tool_calling=True),
|
|
10
10
|
create_model_metadata(provider="OpenAI", name="gpt-4.1-nano", icon="OpenAI", tool_calling=True),
|
|
11
|
-
create_model_metadata(
|
|
11
|
+
create_model_metadata(
|
|
12
|
+
provider="OpenAI", name="gpt-4.5-preview", icon="OpenAI", tool_calling=True, preview=True, not_supported=True
|
|
13
|
+
),
|
|
12
14
|
create_model_metadata(provider="OpenAI", name="gpt-4-turbo", icon="OpenAI", tool_calling=True),
|
|
13
15
|
create_model_metadata(
|
|
14
16
|
provider="OpenAI", name="gpt-4-turbo-preview", icon="OpenAI", tool_calling=True, preview=True
|
|
@@ -17,8 +19,8 @@ OPENAI_MODELS_DETAILED = [
|
|
|
17
19
|
create_model_metadata(provider="OpenAI", name="gpt-3.5-turbo", icon="OpenAI", tool_calling=True),
|
|
18
20
|
# Reasoning Models
|
|
19
21
|
create_model_metadata(provider="OpenAI", name="o1", icon="OpenAI", reasoning=True),
|
|
20
|
-
create_model_metadata(provider="OpenAI", name="o1-mini", icon="OpenAI", reasoning=True),
|
|
21
|
-
create_model_metadata(provider="OpenAI", name="o1-pro", icon="OpenAI", reasoning=True),
|
|
22
|
+
create_model_metadata(provider="OpenAI", name="o1-mini", icon="OpenAI", reasoning=True, not_supported=True),
|
|
23
|
+
create_model_metadata(provider="OpenAI", name="o1-pro", icon="OpenAI", reasoning=True, not_supported=True),
|
|
22
24
|
create_model_metadata(provider="OpenAI", name="o3-mini", icon="OpenAI", reasoning=True),
|
|
23
25
|
create_model_metadata(provider="OpenAI", name="o3", icon="OpenAI", reasoning=True),
|
|
24
26
|
create_model_metadata(provider="OpenAI", name="o3-pro", icon="OpenAI", reasoning=True),
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import re
|
|
3
|
+
|
|
1
4
|
from langchain_core.tools import StructuredTool
|
|
2
5
|
|
|
3
6
|
from langflow.base.agents.agent import LCToolsAgentComponent
|
|
@@ -18,6 +21,7 @@ from langflow.custom.utils import update_component_build_config
|
|
|
18
21
|
from langflow.field_typing import Tool
|
|
19
22
|
from langflow.io import BoolInput, DropdownInput, IntInput, MultilineInput, Output
|
|
20
23
|
from langflow.logging import logger
|
|
24
|
+
from langflow.schema.data import Data
|
|
21
25
|
from langflow.schema.dotdict import dotdict
|
|
22
26
|
from langflow.schema.message import Message
|
|
23
27
|
|
|
@@ -40,6 +44,13 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
40
44
|
|
|
41
45
|
memory_inputs = [set_advanced_true(component_input) for component_input in MemoryComponent().inputs]
|
|
42
46
|
|
|
47
|
+
# Filter out json_mode from OpenAI inputs since we handle structured output differently
|
|
48
|
+
openai_inputs_filtered = [
|
|
49
|
+
input_field
|
|
50
|
+
for input_field in MODEL_PROVIDERS_DICT["OpenAI"]["inputs"]
|
|
51
|
+
if not (hasattr(input_field, "name") and input_field.name == "json_mode")
|
|
52
|
+
]
|
|
53
|
+
|
|
43
54
|
inputs = [
|
|
44
55
|
DropdownInput(
|
|
45
56
|
name="agent_llm",
|
|
@@ -51,7 +62,7 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
51
62
|
input_types=[],
|
|
52
63
|
options_metadata=[MODELS_METADATA[key] for key in MODEL_PROVIDERS_LIST] + [{"icon": "brain"}],
|
|
53
64
|
),
|
|
54
|
-
*
|
|
65
|
+
*openai_inputs_filtered,
|
|
55
66
|
MultilineInput(
|
|
56
67
|
name="system_prompt",
|
|
57
68
|
display_name="Agent Instructions",
|
|
@@ -78,7 +89,10 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
78
89
|
value=True,
|
|
79
90
|
),
|
|
80
91
|
]
|
|
81
|
-
outputs = [
|
|
92
|
+
outputs = [
|
|
93
|
+
Output(name="response", display_name="Response", method="message_response"),
|
|
94
|
+
Output(name="structured_response", display_name="Structured Response", method="json_response", tool_mode=False),
|
|
95
|
+
]
|
|
82
96
|
|
|
83
97
|
async def message_response(self) -> Message:
|
|
84
98
|
try:
|
|
@@ -114,7 +128,11 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
114
128
|
system_prompt=self.system_prompt,
|
|
115
129
|
)
|
|
116
130
|
agent = self.create_agent_runnable()
|
|
117
|
-
|
|
131
|
+
result = await self.run_agent(agent)
|
|
132
|
+
|
|
133
|
+
# Store result for potential JSON output
|
|
134
|
+
self._agent_result = result
|
|
135
|
+
# return result
|
|
118
136
|
|
|
119
137
|
except (ValueError, TypeError, KeyError) as e:
|
|
120
138
|
logger.error(f"{type(e).__name__}: {e!s}")
|
|
@@ -125,6 +143,41 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
125
143
|
except Exception as e:
|
|
126
144
|
logger.error(f"Unexpected error: {e!s}")
|
|
127
145
|
raise
|
|
146
|
+
else:
|
|
147
|
+
return result
|
|
148
|
+
|
|
149
|
+
async def json_response(self) -> Data:
|
|
150
|
+
"""Convert agent response to structured JSON Data output."""
|
|
151
|
+
# Run the regular message response first to get the result
|
|
152
|
+
if not hasattr(self, "_agent_result"):
|
|
153
|
+
await self.message_response()
|
|
154
|
+
|
|
155
|
+
result = self._agent_result
|
|
156
|
+
|
|
157
|
+
# Extract content from result
|
|
158
|
+
if hasattr(result, "content"):
|
|
159
|
+
content = result.content
|
|
160
|
+
elif hasattr(result, "text"):
|
|
161
|
+
content = result.text
|
|
162
|
+
else:
|
|
163
|
+
content = str(result)
|
|
164
|
+
|
|
165
|
+
# Try to parse as JSON
|
|
166
|
+
try:
|
|
167
|
+
json_data = json.loads(content)
|
|
168
|
+
return Data(data=json_data)
|
|
169
|
+
except json.JSONDecodeError:
|
|
170
|
+
# If it's not valid JSON, try to extract JSON from the content
|
|
171
|
+
json_match = re.search(r"\{.*\}", content, re.DOTALL)
|
|
172
|
+
if json_match:
|
|
173
|
+
try:
|
|
174
|
+
json_data = json.loads(json_match.group())
|
|
175
|
+
return Data(data=json_data)
|
|
176
|
+
except json.JSONDecodeError:
|
|
177
|
+
pass
|
|
178
|
+
|
|
179
|
+
# If we can't extract JSON, return the raw content as data
|
|
180
|
+
return Data(data={"content": content, "error": "Could not parse as JSON"})
|
|
128
181
|
|
|
129
182
|
async def get_memory_data(self):
|
|
130
183
|
# TODO: This is a temporary fix to avoid message duplication. We should develop a function for this.
|
|
@@ -171,7 +224,11 @@ class AgentComponent(ToolCallingAgentComponent):
|
|
|
171
224
|
if provider_info:
|
|
172
225
|
inputs = provider_info.get("inputs")
|
|
173
226
|
prefix = provider_info.get("prefix")
|
|
174
|
-
|
|
227
|
+
# Filter out json_mode and only use attributes that exist on this component
|
|
228
|
+
model_kwargs = {}
|
|
229
|
+
for input_ in inputs:
|
|
230
|
+
if hasattr(self, f"{prefix}{input_.name}"):
|
|
231
|
+
model_kwargs[input_.name] = getattr(self, f"{prefix}{input_.name}")
|
|
175
232
|
|
|
176
233
|
return component.set(**model_kwargs)
|
|
177
234
|
return component
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{j as a}from"./index-
|
|
1
|
+
import{j as a}from"./index-rDnX1gJr.js";const s=l=>a.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 54 54",width:"1em",height:"1em",...l,children:a.jsxs("g",{fill:"none",fillRule:"evenodd",children:[a.jsx("path",{fill:"#36C5F0",d:"M19.712.133a5.381 5.381 0 0 0-5.376 5.387 5.381 5.381 0 0 0 5.376 5.386h5.376V5.52A5.381 5.381 0 0 0 19.712.133m0 14.365H5.376A5.381 5.381 0 0 0 0 19.884a5.381 5.381 0 0 0 5.376 5.387h14.336a5.381 5.381 0 0 0 5.376-5.387 5.381 5.381 0 0 0-5.376-5.386"}),a.jsx("path",{fill:"#2EB67D",d:"M53.76 19.884a5.381 5.381 0 0 0-5.376-5.386 5.381 5.381 0 0 0-5.376 5.386v5.387h5.376a5.381 5.381 0 0 0 5.376-5.387m-14.336 0V5.52A5.381 5.381 0 0 0 34.048.133a5.381 5.381 0 0 0-5.376 5.387v14.364a5.381 5.381 0 0 0 5.376 5.387 5.381 5.381 0 0 0 5.376-5.387"}),a.jsx("path",{fill:"#ECB22E",d:"M34.048 54a5.381 5.381 0 0 0 5.376-5.387 5.381 5.381 0 0 0-5.376-5.386h-5.376v5.386A5.381 5.381 0 0 0 34.048 54m0-14.365h14.336a5.381 5.381 0 0 0 5.376-5.386 5.381 5.381 0 0 0-5.376-5.387H34.048a5.381 5.381 0 0 0-5.376 5.387 5.381 5.381 0 0 0 5.376 5.386"}),a.jsx("path",{fill:"#E01E5A",d:"M0 34.249a5.381 5.381 0 0 0 5.376 5.386 5.381 5.381 0 0 0 5.376-5.386v-5.387H5.376A5.381 5.381 0 0 0 0 34.25m14.336-.001v14.364A5.381 5.381 0 0 0 19.712 54a5.381 5.381 0 0 0 5.376-5.387V34.25a5.381 5.381 0 0 0-5.376-5.387 5.381 5.381 0 0 0-5.376 5.387"})]})});export{s as default};
|