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.
Files changed (155) hide show
  1. langflow/alembic/versions/3162e83e485f_add_auth_settings_to_folder_and_merge.py +58 -0
  2. langflow/api/v1/flows.py +11 -1
  3. langflow/api/v1/mcp_projects.py +30 -9
  4. langflow/api/v1/schemas.py +36 -0
  5. langflow/base/models/openai_constants.py +5 -3
  6. langflow/components/agents/agent.py +61 -4
  7. langflow/frontend/assets/{SlackIcon-BEQsp2tG.js → SlackIcon-B1waip4k.js} +1 -1
  8. langflow/frontend/assets/{Wikipedia-CylSh2Rz.js → Wikipedia-C5dnUOP0.js} +1 -1
  9. langflow/frontend/assets/{Wolfram-BbLCNQCI.js → Wolfram-DhcO0RVc.js} +1 -1
  10. langflow/frontend/assets/{index-BwWOFcx9.js → index-3biIaEbi.js} +1 -1
  11. langflow/frontend/assets/{index-fU437Xuh.js → index-418YVFa2.js} +1 -1
  12. langflow/frontend/assets/{index-CmPIFu12.js → index-606CKdUf.js} +1 -1
  13. langflow/frontend/assets/{index-D6qchtKo.js → index-8DyHY_Bk.js} +1 -1
  14. langflow/frontend/assets/{index-DtjOwLQC.js → index-9TR2hnD_.js} +1 -1
  15. langflow/frontend/assets/{index-Buf0FLlA.js → index-B5ZG67DK.js} +1 -1
  16. langflow/frontend/assets/{index-DvZ2dP1K.js → index-B6e8DnbV.js} +1 -1
  17. langflow/frontend/assets/{index-5ls6VK_c.js → index-BBGrtgHW.js} +1 -1
  18. langflow/frontend/assets/{index-C2fMifvM.js → index-BC8MvYGc.js} +1 -1
  19. langflow/frontend/assets/{index-DgghztJk.js → index-BCSQ18YB.js} +1 -1
  20. langflow/frontend/assets/{index-DXMYOwee.js → index-BC_ZSBd8.js} +1 -1
  21. langflow/frontend/assets/{index-BDASu5_h.js → index-BGoj1qt5.js} +1 -1
  22. langflow/frontend/assets/{index-BnRJS1jE.js → index-BHZEUpSJ.js} +1 -1
  23. langflow/frontend/assets/{index-Cqc93Aww.js → index-BMXOUkQC.js} +1 -1
  24. langflow/frontend/assets/{index-CoAX4KHA.js → index-BONWErnQ.js} +1 -1
  25. langflow/frontend/assets/{index-ArQPJTY-.js → index-BSw4Njsa.js} +1 -1
  26. langflow/frontend/assets/{index-cOLi_68F.js → index-BTgluuBN.js} +1 -1
  27. langflow/frontend/assets/{index-B7gZiD-W.js → index-BU-Bn5mu.js} +1 -1
  28. langflow/frontend/assets/{index-DeMmL8Mo.js → index-BYlJ6oLH.js} +1 -1
  29. langflow/frontend/assets/{index-DLoNvjqt.js → index-Bbl1tT9J.js} +1 -1
  30. langflow/frontend/assets/{index-DjNRiQay.js → index-Bf5rmL-A.js} +1 -1
  31. langflow/frontend/assets/{index-ZPrp_qyL.js → index-BfeYY-C1.js} +1 -1
  32. langflow/frontend/assets/{index-DzFPLySG.js → index-BlMOr3_J.js} +1 -1
  33. langflow/frontend/assets/{index-uxytSC6u.js → index-Bn6oRo0n.js} +1 -1
  34. langflow/frontend/assets/{index-Yrff3uIT.js → index-BrG-lJ13.js} +1 -1
  35. langflow/frontend/assets/{index-BjcscQOG.js → index-Bt6nxewq.js} +1 -1
  36. langflow/frontend/assets/{index-CSe6UjxV.js → index-BwVK35FL.js} +1 -1
  37. langflow/frontend/assets/{index-GF2LJgkR.js → index-C-s9qpIS.js} +1 -1
  38. langflow/frontend/assets/{index-CDDBjrKl.js → index-C0HZtOht.js} +1 -1
  39. langflow/frontend/assets/{index-DmZZmu5_.js → index-C3HQLjdj.js} +1 -1
  40. langflow/frontend/assets/{index-Q0Ex46_F.js → index-C5kZL0cq.js} +1 -1
  41. langflow/frontend/assets/{index-DFckK5jC.js → index-C7_J2NrZ.js} +1 -1
  42. langflow/frontend/assets/{index-Bxa7Zqaq.js → index-CALzRXXv.js} +1 -1
  43. langflow/frontend/assets/{index-_AhGSFEp.js → index-CBUjLnxi.js} +1 -1
  44. langflow/frontend/assets/{index-D6iJ0ixS.js → index-CCIWuZBs.js} +1 -1
  45. langflow/frontend/assets/{index-H15pIDqA.js → index-CDEm9KAj.js} +1 -1
  46. langflow/frontend/assets/{index-Dgd8GGgG.js → index-CDSjGlZV.js} +1 -1
  47. langflow/frontend/assets/{index-BxPGc9G_.js → index-CDbyKwTG.js} +1 -1
  48. langflow/frontend/assets/{index-Vx9vra5E.js → index-CDpU78JK.js} +1 -1
  49. langflow/frontend/assets/{index-HbhXQ4iI.js → index-CDuvFcaF.js} +1 -1
  50. langflow/frontend/assets/{index-Bki1gbZ4.js → index-CKPKfZJn.js} +1 -1
  51. langflow/frontend/assets/{index-DaosAMPL.js → index-CLbIIEk2.js} +1 -1
  52. langflow/frontend/assets/{index-C9ZDIZFW.js → index-CPg6geGH.js} +1 -1
  53. langflow/frontend/assets/{index-pwj4p8sb.js → index-CRjDABKd.js} +1 -1
  54. langflow/frontend/assets/{index-B61eUMTR.js → index-CViOvTFf.js} +1 -1
  55. langflow/frontend/assets/{index-lJ1V4apH.js → index-CXUUEanr.js} +1 -1
  56. langflow/frontend/assets/{index-Dj6hJobz.js → index-C_euB6Gl.js} +1 -1
  57. langflow/frontend/assets/{index-BlSZbUqf.js → index-Casu8D9q.js} +1 -1
  58. langflow/frontend/assets/{index-p77FDSRr.js → index-Cg4VEh3c.js} +1 -1
  59. langflow/frontend/assets/{index-O3c1ky7v.js → index-CgIcVOr8.js} +1 -1
  60. langflow/frontend/assets/{index-CEau7eX7.js → index-Cg_tVm4-.js} +1 -1
  61. langflow/frontend/assets/{index-CmSCL35l.js → index-ChqaoD3t.js} +1 -1
  62. langflow/frontend/assets/{index-CdaKd40h.js → index-Cm0S83En.js} +1 -1
  63. langflow/frontend/assets/{index-DEwfBIGT.js → index-CmGwOqUn.js} +1 -1
  64. langflow/frontend/assets/{index-CBOYVi1U.js → index-CsndNop1.js} +1 -1
  65. langflow/frontend/assets/{index-BymhxBmN.js → index-D3JSU9T-.js} +1 -1
  66. langflow/frontend/assets/{index-CDN9FxX3.js → index-D3dEuwpy.js} +1 -1
  67. langflow/frontend/assets/index-D4GoWOiL.css +1 -0
  68. langflow/frontend/assets/{index-KcUnsxlf.js → index-D6ea_8pm.js} +1 -1
  69. langflow/frontend/assets/{index-CJ5EUvrn.js → index-D7Zt_u8q.js} +1 -1
  70. langflow/frontend/assets/{index-BCodFIaO.js → index-D9hSZOYT.js} +1 -1
  71. langflow/frontend/assets/{index-BorUWqkM.js → index-DB7TCTGT.js} +1 -1
  72. langflow/frontend/assets/{index-BRLJm4Du.js → index-DBmHwu6w.js} +1 -1
  73. langflow/frontend/assets/{index-Br2kJx5F.js → index-DCetRusr.js} +1 -1
  74. langflow/frontend/assets/{index-BSZfrTzR.js → index-DFTYUoaZ.js} +1 -1
  75. langflow/frontend/assets/{index-DufevlPT.js → index-DFiKJBMw.js} +1 -1
  76. langflow/frontend/assets/{index-B5S9h8ok.js → index-DH7xKo5T.js} +1 -1
  77. langflow/frontend/assets/{index-DKho7fub.js → index-DKVaEmO7.js} +1 -1
  78. langflow/frontend/assets/{index-BsVHbutF.js → index-DM_Uy5wE.js} +1 -1
  79. langflow/frontend/assets/{index-TUSpXwVe.js → index-DMumbC9j.js} +1 -1
  80. langflow/frontend/assets/{index-D_AWHRfe.js → index-DOD107en.js} +1 -1
  81. langflow/frontend/assets/{index-DNOP-INQ.js → index-DOW9ZSLB.js} +1 -1
  82. langflow/frontend/assets/{index-CogD177T.js → index-DQHDRmym.js} +1 -1
  83. langflow/frontend/assets/{index-D8nmnanz.js → index-DUE44GEX.js} +1 -1
  84. langflow/frontend/assets/{index-k9UFhzxg.js → index-DYrXxgrb.js} +1 -1
  85. langflow/frontend/assets/{index-CdPp99Ov.js → index-DYv6Aras.js} +1 -1
  86. langflow/frontend/assets/{index-gsz-bhOF.js → index-DZgXMtLr.js} +1 -1
  87. langflow/frontend/assets/{index-DpMb4SyP.js → index-Dcalb9GV.js} +1 -1
  88. langflow/frontend/assets/{index-B2VOPfSQ.js → index-DgAnAkZI.js} +1 -1
  89. langflow/frontend/assets/{index-C3Bj4_FP.js → index-Dh4QIx-9.js} +1 -1
  90. langflow/frontend/assets/{index-DJzLRh66.js → index-DiC6aHWh.js} +1 -1
  91. langflow/frontend/assets/{index-C9dL6qYU.js → index-DjQo2TKu.js} +1 -1
  92. langflow/frontend/assets/{index-ChyV4bY1.js → index-Dm2EC55c.js} +1 -1
  93. langflow/frontend/assets/{index-YXNg_MqK.js → index-Dn6DEQeW.js} +1 -1
  94. langflow/frontend/assets/{index-D2K8Dxca.js → index-DpVlWsbf.js} +1 -1
  95. langflow/frontend/assets/{index-UVKuDcRW.js → index-DpxIP5eR.js} +1 -1
  96. langflow/frontend/assets/{index-Bhm1dylP.js → index-DtNmksPw.js} +1 -1
  97. langflow/frontend/assets/{index-lp0TR1VG.js → index-DvZa-h7F.js} +1 -1
  98. langflow/frontend/assets/{index-DcTv_MVV.js → index-DvfpMNxC.js} +1 -1
  99. langflow/frontend/assets/{index-BtXZCxsi.js → index-DwSpFzJE.js} +1 -1
  100. langflow/frontend/assets/{index-CBGa-ML1.js → index-Dxt2wnqB.js} +1 -1
  101. langflow/frontend/assets/{index-DYwMDNLL.js → index-Dym17axM.js} +1 -1
  102. langflow/frontend/assets/{index-C9KrGJ67.js → index-FRFezpnl.js} +1 -1
  103. langflow/frontend/assets/{index-dg4h4aV9.js → index-JXRrBiMq.js} +1 -1
  104. langflow/frontend/assets/{index-DZ4RRuo1.js → index-JnJLq8vw.js} +1 -1
  105. langflow/frontend/assets/{index-DysqOh2v.js → index-Lj5U_BEs.js} +1 -1
  106. langflow/frontend/assets/{index-ChPNbgSb.js → index-MzhQqWgp.js} +1 -1
  107. langflow/frontend/assets/{index-CtzhOjCJ.js → index-Nrq24q0b.js} +1 -1
  108. langflow/frontend/assets/{index-Dgtl-Ryc.js → index-PR9CDiB2.js} +1 -1
  109. langflow/frontend/assets/{index-kjgyrJKk.js → index-Ps_-SFhI.js} +1 -1
  110. langflow/frontend/assets/{index-DyIpqQ6u.js → index-QtS6b7Sw.js} +1 -1
  111. langflow/frontend/assets/{index-D38ii1eC.js → index-SG4iMGMH.js} +1 -1
  112. langflow/frontend/assets/{index-C_H9PvPC.js → index-VgSSRzOC.js} +1 -1
  113. langflow/frontend/assets/{index-CbN90tiv.js → index-VroAkSXX.js} +1 -1
  114. langflow/frontend/assets/{index-DCNa4h3y.js → index-XRYx-9PH.js} +1 -1
  115. langflow/frontend/assets/{index-DGV6oDTb.js → index-X_N2VjCI.js} +1 -1
  116. langflow/frontend/assets/{index-Bpv14pFu.js → index-ZEtb94y9.js} +1 -1
  117. langflow/frontend/assets/{index-ZHQE-way.js → index-ZdUecE-Q.js} +1 -1
  118. langflow/frontend/assets/{index-CcS86fAH.js → index-eGM7b_zA.js} +1 -1
  119. langflow/frontend/assets/{index-N3NiikE-.js → index-ewyyoy2D.js} +1 -1
  120. langflow/frontend/assets/{index-GUM5ctOD.js → index-gY4GknXS.js} +1 -1
  121. langflow/frontend/assets/{index-BTPSO7Ty.js → index-gm2XOLA2.js} +1 -1
  122. langflow/frontend/assets/{index--afKjQV4.js → index-ipP5SzLr.js} +1 -1
  123. langflow/frontend/assets/{index-BUepyNwR.js → index-is0kQpz3.js} +1 -1
  124. langflow/frontend/assets/{index-DiYhK7Hs.js → index-kElqCHmt.js} +1 -1
  125. langflow/frontend/assets/{index-DYj_t4sx.js → index-kQTNfH4u.js} +1 -1
  126. langflow/frontend/assets/{index-gnvplQfi.js → index-m4Hpi_aX.js} +1 -1
  127. langflow/frontend/assets/{index-DOZ4j-co.js → index-nLSeiMV2.js} +1 -1
  128. langflow/frontend/assets/{index-B1yGg3ui.js → index-rDnX1gJr.js} +1907 -1907
  129. langflow/frontend/assets/{index-CTIjE6ec.js → index-zO8eyFDr.js} +1 -1
  130. langflow/frontend/assets/lazyIconImports-GHEHdmsf.js +2 -0
  131. langflow/frontend/assets/{use-post-add-user-CNxc7cHz.js → use-post-add-user-BanYOJbs.js} +1 -1
  132. langflow/frontend/index.html +2 -2
  133. langflow/initial_setup/starter_projects/Instagram Copywriter.json +147 -100
  134. langflow/initial_setup/starter_projects/Invoice Summarizer.json +1 -1
  135. langflow/initial_setup/starter_projects/Market Research.json +1 -1
  136. langflow/initial_setup/starter_projects/News Aggregator.json +1 -1
  137. langflow/initial_setup/starter_projects/Nvidia Remix.json +1 -1
  138. langflow/initial_setup/starter_projects/Pok/303/251dex Agent.json" +1 -1
  139. langflow/initial_setup/starter_projects/Price Deal Finder.json +1 -1
  140. langflow/initial_setup/starter_projects/Research Agent.json +1 -1
  141. langflow/initial_setup/starter_projects/SaaS Pricing.json +1 -1
  142. langflow/initial_setup/starter_projects/Search agent.json +1 -1
  143. langflow/initial_setup/starter_projects/Sequential Tasks Agents.json +3 -3
  144. langflow/initial_setup/starter_projects/Simple Agent.json +1 -1
  145. langflow/initial_setup/starter_projects/Social Media Agent.json +1 -1
  146. langflow/initial_setup/starter_projects/Travel Planning Agents.json +3 -3
  147. langflow/initial_setup/starter_projects/Youtube Analysis.json +1 -1
  148. langflow/services/database/models/folder/model.py +7 -1
  149. langflow/services/settings/feature_flags.py +1 -0
  150. {langflow_base_nightly-0.5.0.dev11.dist-info → langflow_base_nightly-0.5.0.dev13.dist-info}/METADATA +1 -1
  151. {langflow_base_nightly-0.5.0.dev11.dist-info → langflow_base_nightly-0.5.0.dev13.dist-info}/RECORD +153 -152
  152. langflow/frontend/assets/index-MB8UM6Ob.css +0 -1
  153. langflow/frontend/assets/lazyIconImports-B2rERpGa.js +0 -2
  154. {langflow_base_nightly-0.5.0.dev11.dist-info → langflow_base_nightly-0.5.0.dev13.dist-info}/WHEEL +0 -0
  155. {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
- extract_number = re.compile(r"\((\d+)\)$")
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
@@ -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 MCPInstallRequest, MCPSettings
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
- ) -> list[MCPSettings]:
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
- settings: list[MCPSettings],
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
- args = ["mcp-proxy", sse_url]
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", "mcp-proxy", sse_url]
405
+ args = ["/c", "uvx", mcp_tool, sse_url]
385
406
  logger.debug("Windows detected, using cmd command")
386
407
 
387
408
  name = project.name
@@ -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(provider="OpenAI", name="gpt-4.5-preview", icon="OpenAI", tool_calling=True, preview=True),
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
- *MODEL_PROVIDERS_DICT["OpenAI"]["inputs"],
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 = [Output(name="response", display_name="Response", method="message_response")]
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
- return await self.run_agent(agent)
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
- model_kwargs = {input_.name: getattr(self, f"{prefix}{input_.name}") for input_ in inputs}
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-B1yGg3ui.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};
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};