langflow-base-nightly 0.5.1.dev3__py3-none-any.whl → 0.5.1.dev4__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 (935) hide show
  1. langflow/__init__.py +215 -0
  2. langflow/__main__.py +16 -2
  3. langflow/alembic/versions/006b3990db50_add_unique_constraints.py +4 -7
  4. langflow/alembic/versions/012fb73ac359_add_folder_table.py +4 -5
  5. langflow/alembic/versions/0ae3a2674f32_update_the_columns_that_need_to_change_.py +11 -20
  6. langflow/alembic/versions/0b8757876a7c_.py +4 -7
  7. langflow/alembic/versions/0d60fcbd4e8e_create_vertex_builds_table.py +4 -6
  8. langflow/alembic/versions/1a110b568907_replace_credential_table_with_variable.py +4 -5
  9. langflow/alembic/versions/1b8b740a6fa3_remove_fk_constraint_in_message_.py +32 -27
  10. langflow/alembic/versions/1c79524817ed_add_unique_constraints_per_user_in_.py +4 -5
  11. langflow/alembic/versions/1d90f8a0efe1_update_description_columns_type.py +4 -5
  12. langflow/alembic/versions/1eab2c3eb45e_event_error.py +14 -15
  13. langflow/alembic/versions/1ef9c4f3765d_.py +5 -10
  14. langflow/alembic/versions/1f4d6df60295_add_default_fields_column.py +4 -5
  15. langflow/alembic/versions/260dbcc8b680_adds_tables.py +4 -5
  16. langflow/alembic/versions/29fe8f1f806b_add_missing_index.py +4 -5
  17. langflow/alembic/versions/2ac71eb9c3ae_adds_credential_table.py +4 -7
  18. langflow/alembic/versions/3bb0ddf32dfb_add_unique_constraints_per_user_in_flow_.py +4 -5
  19. langflow/alembic/versions/4e5980a44eaa_fix_date_times_again.py +1 -2
  20. langflow/alembic/versions/58b28437a398_modify_nullable.py +1 -2
  21. langflow/alembic/versions/5ace73a7f223_new_remove_table_upgrade_op.py +6 -12
  22. langflow/alembic/versions/631faacf5da2_add_webhook_columns.py +4 -5
  23. langflow/alembic/versions/63b9c451fd30_add_icon_and_icon_bg_color_to_flow.py +4 -5
  24. langflow/alembic/versions/66f72f04a1de_add_mcp_support_with_project_settings_.py +21 -23
  25. langflow/alembic/versions/67cc006d50bf_add_profile_image_column.py +4 -5
  26. langflow/alembic/versions/6e7b581b5648_fix_nullable.py +4 -5
  27. langflow/alembic/versions/7843803a87b5_store_updates.py +4 -6
  28. langflow/alembic/versions/79e675cb6752_change_datetime_type.py +1 -2
  29. langflow/alembic/versions/7d2162acc8b2_adds_updated_at_and_folder_cols.py +4 -10
  30. langflow/alembic/versions/90be8e2ed91e_create_transactions_table.py +4 -6
  31. langflow/alembic/versions/93e2705fa8d6_add_column_save_path_to_flow.py +7 -9
  32. langflow/alembic/versions/a72f5cf9c2f9_add_endpoint_name_col.py +4 -5
  33. langflow/alembic/versions/b2fa308044b5_add_unique_constraints.py +1 -2
  34. langflow/alembic/versions/bc2f01c40e4a_new_fixes.py +4 -5
  35. langflow/alembic/versions/c153816fd85f_set_name_and_value_to_not_nullable.py +4 -5
  36. langflow/alembic/versions/d066bfd22890_add_message_table.py +4 -4
  37. langflow/alembic/versions/d2d475a1f7c0_add_tags_column_to_flow.py +12 -13
  38. langflow/alembic/versions/d3dbf656a499_add_gradient_column_in_flow.py +12 -12
  39. langflow/alembic/versions/d9a6ea21edcd_rename_default_folder.py +7 -10
  40. langflow/alembic/versions/dd9e0804ebd1_add_v2_file_table.py +8 -7
  41. langflow/alembic/versions/e3162c1804e6_add_persistent_locked_state.py +10 -10
  42. langflow/alembic/versions/e3bc869fa272_fix_nullable.py +4 -5
  43. langflow/alembic/versions/e56d87f8994a_add_optins_column_to_user.py +13 -14
  44. langflow/alembic/versions/e5a65ecff2cd_nullable_in_vertex_build.py +4 -5
  45. langflow/alembic/versions/eb5866d51fd2_change_columns_to_be_nullable.py +4 -5
  46. langflow/alembic/versions/eb5e72293a8e_add_error_and_edit_flags_to_message.py +4 -5
  47. langflow/alembic/versions/f3b2d1f1002d_add_column_access_type_to_flow.py +19 -15
  48. langflow/alembic/versions/f5ee9749d1a6_user_id_can_be_null_in_flow.py +4 -6
  49. langflow/alembic/versions/fd531f8868b1_fix_credential_table.py +5 -8
  50. langflow/api/build.py +5 -4
  51. langflow/api/health_check_router.py +1 -1
  52. langflow/api/limited_background_tasks.py +1 -1
  53. langflow/api/log_router.py +1 -2
  54. langflow/api/utils.py +2 -2
  55. langflow/api/v1/base.py +1 -2
  56. langflow/api/v1/callback.py +4 -9
  57. langflow/api/v1/chat.py +6 -7
  58. langflow/api/v1/endpoints.py +15 -15
  59. langflow/api/v1/files.py +1 -1
  60. langflow/api/v1/flows.py +1 -1
  61. langflow/api/v1/knowledge_bases.py +1 -1
  62. langflow/api/v1/mcp.py +1 -1
  63. langflow/api/v1/mcp_projects.py +14 -5
  64. langflow/api/v1/mcp_utils.py +3 -3
  65. langflow/api/v1/openai_responses.py +4 -4
  66. langflow/api/v1/schemas.py +3 -38
  67. langflow/api/v1/starter_projects.py +61 -3
  68. langflow/api/v1/store.py +1 -1
  69. langflow/api/v1/validate.py +3 -3
  70. langflow/api/v1/voice_mode.py +2 -2
  71. langflow/api/v2/files.py +1 -1
  72. langflow/api/v2/mcp.py +2 -2
  73. langflow/base/__init__.py +11 -0
  74. langflow/base/agents/__init__.py +3 -0
  75. langflow/base/data/__init__.py +2 -4
  76. langflow/base/data/utils.py +2 -197
  77. langflow/base/embeddings/__init__.py +3 -0
  78. langflow/base/io/__init__.py +7 -0
  79. langflow/base/io/chat.py +5 -18
  80. langflow/base/io/text.py +2 -21
  81. langflow/base/knowledge_bases/__init__.py +3 -0
  82. langflow/base/memory/__init__.py +3 -0
  83. langflow/base/models/__init__.py +2 -2
  84. langflow/base/models/openai_constants.py +6 -120
  85. langflow/base/prompts/__init__.py +3 -0
  86. langflow/base/prompts/api_utils.py +2 -223
  87. langflow/base/textsplitters/__init__.py +3 -0
  88. langflow/base/tools/__init__.py +3 -0
  89. langflow/base/vectorstores/__init__.py +3 -0
  90. langflow/components/__init__.py +7 -259
  91. langflow/components/agents.py +6 -0
  92. langflow/components/anthropic.py +6 -0
  93. langflow/components/data.py +6 -0
  94. langflow/components/helpers.py +6 -0
  95. langflow/components/knowledge_bases/ingestion.py +13 -14
  96. langflow/components/knowledge_bases/retrieval.py +8 -7
  97. langflow/components/openai.py +6 -0
  98. langflow/components/processing/__init__.py +1 -117
  99. langflow/components/processing/converter.py +3 -149
  100. langflow/custom/__init__.py +26 -3
  101. langflow/custom/custom_component/__init__.py +4 -0
  102. langflow/custom/custom_component/component.py +20 -1738
  103. langflow/custom/custom_component/component_with_cache.py +1 -8
  104. langflow/custom/custom_component/custom_component.py +1 -552
  105. langflow/custom/utils.py +1 -872
  106. langflow/custom/validate.py +1 -0
  107. langflow/events/event_manager.py +18 -108
  108. langflow/field_typing/__init__.py +6 -6
  109. langflow/field_typing/constants.py +87 -122
  110. langflow/field_typing/range_spec.py +2 -32
  111. langflow/frontend/assets/{SlackIcon-Cc7Qnzki.js → SlackIcon-v88osOTA.js} +1 -1
  112. langflow/frontend/assets/{Wikipedia-7ulMZY46.js → Wikipedia-DD_S2k00.js} +1 -1
  113. langflow/frontend/assets/{Wolfram-By9PGsHS.js → Wolfram-EO2C5noN.js} +1 -1
  114. langflow/frontend/assets/{index-DVLIDc2_.js → index-1Gv1mfvk.js} +1 -1
  115. langflow/frontend/assets/{index-MVW4HTEk.js → index-7v-bzlzf.js} +1 -1
  116. langflow/frontend/assets/{index-CUzlcce2.js → index-9CbMazbV.js} +1 -1
  117. langflow/frontend/assets/{index-CU16NJD7.js → index-B8ZHP8g2.js} +1 -1
  118. langflow/frontend/assets/{index-v8eXbWlM.js → index-B8y2e6vN.js} +1 -1
  119. langflow/frontend/assets/{index-BX_asvRB.js → index-BBRUGsyr.js} +1 -1
  120. langflow/frontend/assets/{index-9FL5xjkL.js → index-BGwqQwlh.js} +1 -1
  121. langflow/frontend/assets/{index-BAn-AzCS.js → index-BIq-k-FG.js} +1 -1
  122. langflow/frontend/assets/{index-D5c2nNvp.js → index-BSN73YP8.js} +1 -1
  123. langflow/frontend/assets/{index-DMCerPJM.js → index-BU8R8jRn.js} +1 -1
  124. langflow/frontend/assets/{index-CvSoff-8.js → index-BV6yx8ey.js} +1 -1
  125. langflow/frontend/assets/{index-BISPW-f6.js → index-BYIsg-Eh.js} +1 -1
  126. langflow/frontend/assets/{index-GzOGB_fo.js → index-B_ksDBSQ.js} +1 -1
  127. langflow/frontend/assets/{index-BIqEYjNT.js → index-Ba1UOZ9A.js} +1 -1
  128. langflow/frontend/assets/{index-ByxGmq5p.js → index-Ba9tKRQg.js} +1 -1
  129. langflow/frontend/assets/{index-BLEWsL1U.js → index-Bbfaw8ca.js} +1 -1
  130. langflow/frontend/assets/{index-C_MhBX6R.js → index-BbuGqvAx.js} +1 -1
  131. langflow/frontend/assets/{index-RH_I78z_.js → index-BeoXu1YX.js} +1 -1
  132. langflow/frontend/assets/{index-cYFKmtmg.js → index-BfjZmOnH.js} +1 -1
  133. langflow/frontend/assets/{index-Bm9i8F4W.js → index-Bjzy_HZB.js} +1 -1
  134. langflow/frontend/assets/{index-_szO7sta.js → index-BofEkpYB.js} +1 -1
  135. langflow/frontend/assets/{index-DP1oE6QB.js → index-Bp7Mty2H.js} +1 -1
  136. langflow/frontend/assets/{index-CeswGUz3.js → index-BqX1H6yK.js} +1 -1
  137. langflow/frontend/assets/{index-C8pI0lzi.js → index-BqtBAJAN.js} +1 -1
  138. langflow/frontend/assets/{index-BusCv3bR.js → index-Bsfraj7A.js} +1 -1
  139. langflow/frontend/assets/{index-BWnKMRFJ.js → index-BtFl7fER.js} +1 -1
  140. langflow/frontend/assets/{index-DnlVWWU8.js → index-BvX993Sv.js} +1 -1
  141. langflow/frontend/assets/{index-C676MS3I.js → index-BvgQ2vzM.js} +1 -1
  142. langflow/frontend/assets/{index-DJ6HD14g.js → index-BwY98u8n.js} +1 -1
  143. langflow/frontend/assets/{index-C51yNvIL.js → index-C-RIJAOS.js} +1 -1
  144. langflow/frontend/assets/{index-DiblXWmk.js → index-C1K6A38P.js} +1 -1
  145. langflow/frontend/assets/{index-Co__gFM1.js → index-C3Vwhx0t.js} +1 -1
  146. langflow/frontend/assets/{index-Coi86oqP.js → index-C5XUG_gr.js} +1 -1
  147. langflow/frontend/assets/{index-jwzN3Jd_.js → index-C6ouLG9o.js} +1 -1
  148. langflow/frontend/assets/{index-CQQ-4XMS.js → index-C7ZJ_Z6f.js} +1 -1
  149. langflow/frontend/assets/{index-Bl7RpmrB.js → index-CCOGIwGY.js} +1 -1
  150. langflow/frontend/assets/{index-CVkIdc6y.js → index-CCcye2rt.js} +1 -1
  151. langflow/frontend/assets/{index-bMhyLtgS.js → index-CFR4yJQB.js} +1 -1
  152. langflow/frontend/assets/{index-aAgSKWb3.js → index-CIGmPP0H.js} +1 -1
  153. langflow/frontend/assets/{index-BGt6jQ4x.js → index-CJmMEa6d.js} +1 -1
  154. langflow/frontend/assets/{index-DX7JcSMz.js → index-CJxD7lyU.js} +1 -1
  155. langflow/frontend/assets/{index-BZ-A4K98.js → index-CL_vu6ut.js} +1 -1
  156. langflow/frontend/assets/{index-BMpKFGhI.js → index-COf3UnBn.js} +1 -1
  157. langflow/frontend/assets/{index-xN8ogFdo.js → index-CV9650h_.js} +1 -1
  158. langflow/frontend/assets/{index-OsUvqIUr.js → index-CVDzych0.js} +1 -1
  159. langflow/frontend/assets/{index-BH7AyHxp.js → index-CWIHsC4D.js} +1 -1
  160. langflow/frontend/assets/{index-mjwtJmkP.js → index-CXCnFZ0L.js} +1 -1
  161. langflow/frontend/assets/{index-3jlSQi5Y.js → index-Ca_Pw_Dn.js} +1 -1
  162. langflow/frontend/assets/{index-D-SnFlhU.js → index-Cbb3bX9e.js} +1 -1
  163. langflow/frontend/assets/{index--e0oQqZh.js → index-CcJtOz-Z.js} +1 -1
  164. langflow/frontend/assets/{index-S-sc0Cm9.js → index-CfTbTHEv.js} +1 -1
  165. langflow/frontend/assets/{index-Deu8rlaZ.js → index-ChoxDAgX.js} +1 -1
  166. langflow/frontend/assets/{index-lnF9Eqr2.js → index-Cn4gw8aE.js} +1 -1
  167. langflow/frontend/assets/{index-C_NwzK6j.js → index-CnpLg4zX.js} +1 -1
  168. langflow/frontend/assets/{index-DznH7Jbq.js → index-Cpao2omG.js} +1 -1
  169. langflow/frontend/assets/{index-DpWrk8mA.js → index-CqoxM01j.js} +1 -1
  170. langflow/frontend/assets/{index-Bw-TIIC6.js → index-CrHf2Ic1.js} +1 -1
  171. langflow/frontend/assets/{index-DmYLDQag.js → index-CrV0uIjp.js} +1 -1
  172. langflow/frontend/assets/{index-Dp7ZQyL3.js → index-CssADaak.js} +1 -1
  173. langflow/frontend/assets/{index-CNh0rwur.js → index-CtJdNLy9.js} +1 -1
  174. langflow/frontend/assets/{index-Ca1b7Iag.js → index-CyeWD2dh.js} +1 -1
  175. langflow/frontend/assets/{index-DcApTyZ7.js → index-D1xzD7uc.js} +1 -1
  176. langflow/frontend/assets/{index-B3GvPjhD.js → index-D6MuXC4L.js} +1 -1
  177. langflow/frontend/assets/{index-Cw0UComa.js → index-D8w9zvIF.js} +1 -1
  178. langflow/frontend/assets/{index-C-2MRYoJ.js → index-D98Gn0A6.js} +1 -1
  179. langflow/frontend/assets/{index-aWnZIwHd.js → index-DBhjpWkf.js} +1 -1
  180. langflow/frontend/assets/{index-nw3WF9lY.js → index-DCCRJzcY.js} +1 -1
  181. langflow/frontend/assets/{index-RjeC0kaX.js → index-DCTRSkEW.js} +1 -1
  182. langflow/frontend/assets/{index-B_kBTgxV.js → index-DCUfitVj.js} +1 -1
  183. langflow/frontend/assets/{index-ChsGhZn3.js → index-DDdz-Xcl.js} +1 -1
  184. langflow/frontend/assets/{index-7yAHPRxv.js → index-DGdMwZjG.js} +1 -1
  185. langflow/frontend/assets/{index-DjQElpEg.js → index-DGtl2vMw.js} +1 -1
  186. langflow/frontend/assets/{index-BCXhKCOK.js → index-DHVdkrni.js} +1 -1
  187. langflow/frontend/assets/{index-S8uJXTOq.js → index-DJBWwjgl.js} +1 -1
  188. langflow/frontend/assets/{index-qiVTWUuf.js → index-DMAkJ_qX.js} +1 -1
  189. langflow/frontend/assets/{index-D-WStJI6.js → index-DMEvEQI5.js} +1 -1
  190. langflow/frontend/assets/{index-BhqVw9WQ.js → index-DNGRoOsp.js} +1 -1
  191. langflow/frontend/assets/{index-Cu7vC48Y.js → index-DNT_TUTa.js} +1 -1
  192. langflow/frontend/assets/{index-Bhcv5M0n.js → index-DQKOH_9K.js} +1 -1
  193. langflow/frontend/assets/{index-CLcaktde.js → index-DQhqqtqQ.js} +1 -1
  194. langflow/frontend/assets/{index-DZVgPCio.js → index-DRM7KKnG.js} +1 -1
  195. langflow/frontend/assets/{index-uybez8MR.js → index-DSCtl3a5.js} +1 -1
  196. langflow/frontend/assets/{index-CJ5A6STv.js → index-DSLNlm0Z.js} +1 -1
  197. langflow/frontend/assets/{index-Drg8me2a.js → index-DT-PspE-.js} +1 -1
  198. langflow/frontend/assets/{index-DsEZjOcp.js → index-DTpbH-p8.js} +1 -1
  199. langflow/frontend/assets/{index-DrXXKzpD.js → index-DWV6MsIq.js} +1 -1
  200. langflow/frontend/assets/{index-4JIEdyIM.js → index-DWeL4US_.js} +1 -1
  201. langflow/frontend/assets/{index-BlDsBQ_1.js → index-DYKZHhpU.js} +1 -1
  202. langflow/frontend/assets/{index-DFY8YFbC.js → index-DZyQHiMR.js} +1 -1
  203. langflow/frontend/assets/{index-CKPZpkQk.js → index-Dc6qVuSa.js} +1 -1
  204. langflow/frontend/assets/{index-yyAaYjLR.js → index-DkYuicnC.js} +1 -1
  205. langflow/frontend/assets/{index-DmVt5Jlx.js → index-Dlj_2mMs.js} +1 -1
  206. langflow/frontend/assets/{index-BvRIG6P5.js → index-DmGJUrEp.js} +1 -1
  207. langflow/frontend/assets/{index-BWFIrwW1.js → index-Dn6hpCAZ.js} +1 -1
  208. langflow/frontend/assets/{index-Cb5G9Ifd.js → index-DrJU8Fgb.js} +1 -1
  209. langflow/frontend/assets/{index-COoTCxvs.js → index-DsWfdCzp.js} +1 -1
  210. langflow/frontend/assets/{index-ZjeocHyu.js → index-DvCPWs2_.js} +1 -1
  211. langflow/frontend/assets/{index-B5LHnuQR.js → index-DvPVq7OP.js} +1 -1
  212. langflow/frontend/assets/{index-BnCnYnao.js → index-Dw71ufW4.js} +1 -1
  213. langflow/frontend/assets/{index-AALDfCyt.js → index-DxkJactf.js} +1 -1
  214. langflow/frontend/assets/{index-k9jP5chN.js → index-Dz2GTphU.js} +1 -1
  215. langflow/frontend/assets/{index-BdjfHsrf.js → index-Fvd524_c.js} +1 -1
  216. langflow/frontend/assets/{index-AKVkmT4S.js → index-GAQ0Mk2M.js} +1 -1
  217. langflow/frontend/assets/{index-BZSa2qz7.js → index-Hm5-4ItD.js} +1 -1
  218. langflow/frontend/assets/{index-DbfS_UH-.js → index-IT67FzsK.js} +1 -1
  219. langflow/frontend/assets/{index-BLXN681C.js → index-ItYiij1i.js} +1 -1
  220. langflow/frontend/assets/{index-CiklyQU3.js → index-IuR_FEdB.js} +1 -1
  221. langflow/frontend/assets/{index-xV6ystWy.js → index-Jj60FQkv.js} +1 -1
  222. langflow/frontend/assets/{index-C_157Mb-.js → index-LlvshmVz.js} +1 -1
  223. langflow/frontend/assets/{index-CDphUsa3.js → index-LwKh3I_W.js} +1 -1
  224. langflow/frontend/assets/{index-BrDz-PxE.js → index-N-xxmKKH.js} +1 -1
  225. langflow/frontend/assets/{index-BsdLyYMY.js → index-RwpaHIAH.js} +1 -1
  226. langflow/frontend/assets/{index-Cu2Xr6_j.js → index-TVvsp-xh.js} +1 -1
  227. langflow/frontend/assets/{index-CPiM2oyj.js → index-TdE2u9zP.js} +1 -1
  228. langflow/frontend/assets/{index-DOj_QWqG.js → index-_x-NkYeW.js} +1 -1
  229. langflow/frontend/assets/{index-YJsAl7vm.js → index-a-YclEbW.js} +1 -1
  230. langflow/frontend/assets/{index-5-CSw2-z.js → index-e9MFKUCo.js} +1 -1
  231. langflow/frontend/assets/{index-BSwBVwyF.js → index-krPr8f2F.js} +1 -1
  232. langflow/frontend/assets/{index-Df6psZEj.js → index-kveiUWuL.js} +1 -1
  233. langflow/frontend/assets/{index-CF4_Og1m.js → index-lE3oSjJi.js} +1 -1
  234. langflow/frontend/assets/{index-C6nzdeYx.js → index-lM3UYg7F.js} +1 -1
  235. langflow/frontend/assets/{index-C-wnbBBY.js → index-nsRk3qgA.js} +1 -1
  236. langflow/frontend/assets/{index-D234yKNJ.js → index-pBO0SZLD.js} +4 -4
  237. langflow/frontend/assets/{index-BMvp94tO.js → index-pbZHsbuE.js} +1 -1
  238. langflow/frontend/assets/{index-hg2y9OAt.js → index-sfX3aWyp.js} +1 -1
  239. langflow/frontend/assets/{index-DTCrijba.js → index-xQz-VJ0-.js} +1 -1
  240. langflow/frontend/assets/{index-SB4rw8D5.js → index-yfcsaHS6.js} +1 -1
  241. langflow/frontend/assets/{index-C-bjC2sz.js → index-zcGjo9fx.js} +1 -1
  242. langflow/frontend/assets/lazyIconImports-BjqDmNYG.js +2 -0
  243. langflow/frontend/assets/{use-post-add-user-JUeLDErC.js → use-post-add-user-w3vpKSOB.js} +1 -1
  244. langflow/frontend/index.html +1 -1
  245. langflow/graph/__init__.py +4 -4
  246. langflow/helpers/data.py +2 -2
  247. langflow/helpers/flow.py +9 -7
  248. langflow/helpers/user.py +2 -2
  249. langflow/initial_setup/setup.py +9 -9
  250. langflow/initial_setup/starter_projects/Basic Prompt Chaining.json +119 -41
  251. langflow/initial_setup/starter_projects/Basic Prompting.json +45 -19
  252. langflow/initial_setup/starter_projects/Blog Writer.json +53 -21
  253. langflow/initial_setup/starter_projects/Custom Component Generator.json +121 -97
  254. langflow/initial_setup/starter_projects/Document Q&A.json +46 -18
  255. langflow/initial_setup/starter_projects/Financial Report Parser.json +49 -17
  256. langflow/initial_setup/starter_projects/Hybrid Search RAG.json +89 -50
  257. langflow/initial_setup/starter_projects/Image Sentiment Analysis.json +86 -22
  258. langflow/initial_setup/starter_projects/Instagram Copywriter.json +210 -57
  259. langflow/initial_setup/starter_projects/Invoice Summarizer.json +132 -35
  260. langflow/initial_setup/starter_projects/Knowledge Ingestion.json +8 -8
  261. langflow/initial_setup/starter_projects/Knowledge Retrieval.json +8 -8
  262. langflow/initial_setup/starter_projects/Market Research.json +174 -48
  263. langflow/initial_setup/starter_projects/Meeting Summary.json +102 -38
  264. langflow/initial_setup/starter_projects/Memory Chatbot.json +49 -21
  265. langflow/initial_setup/starter_projects/News Aggregator.json +140 -39
  266. langflow/initial_setup/starter_projects/Nvidia Remix.json +153 -181
  267. langflow/initial_setup/starter_projects/Pok/303/251dex Agent.json" +132 -35
  268. langflow/initial_setup/starter_projects/Portfolio Website Code Generator.json +106 -43
  269. langflow/initial_setup/starter_projects/Price Deal Finder.json +136 -39
  270. langflow/initial_setup/starter_projects/Research Agent.json +206 -53
  271. langflow/initial_setup/starter_projects/Research Translation Loop.json +66 -34
  272. langflow/initial_setup/starter_projects/SEO Keyword Generator.json +41 -15
  273. langflow/initial_setup/starter_projects/SaaS Pricing.json +128 -31
  274. langflow/initial_setup/starter_projects/Search agent.json +132 -35
  275. langflow/initial_setup/starter_projects/Sequential Tasks Agents.json +422 -98
  276. langflow/initial_setup/starter_projects/Simple Agent.json +150 -42
  277. langflow/initial_setup/starter_projects/Social Media Agent.json +150 -42
  278. langflow/initial_setup/starter_projects/Text Sentiment Analysis.json +120 -24
  279. langflow/initial_setup/starter_projects/Travel Planning Agents.json +418 -94
  280. langflow/initial_setup/starter_projects/Twitter Thread Generator.json +69 -37
  281. langflow/initial_setup/starter_projects/Vector Store RAG.json +66 -38
  282. langflow/initial_setup/starter_projects/Youtube Analysis.json +191 -51
  283. langflow/initial_setup/starter_projects/basic_prompting.py +4 -4
  284. langflow/initial_setup/starter_projects/blog_writer.py +5 -5
  285. langflow/initial_setup/starter_projects/complex_agent.py +8 -8
  286. langflow/initial_setup/starter_projects/document_qa.py +5 -5
  287. langflow/initial_setup/starter_projects/hierarchical_tasks_agent.py +8 -8
  288. langflow/initial_setup/starter_projects/memory_chatbot.py +6 -6
  289. langflow/initial_setup/starter_projects/sequential_tasks_agent.py +7 -7
  290. langflow/initial_setup/starter_projects/vector_store_rag.py +8 -8
  291. langflow/inputs/__init__.py +3 -2
  292. langflow/inputs/constants.py +3 -2
  293. langflow/inputs/input_mixin.py +49 -310
  294. langflow/inputs/inputs.py +72 -703
  295. langflow/inputs/validators.py +2 -18
  296. langflow/interface/__init__.py +4 -0
  297. langflow/interface/components.py +3 -491
  298. langflow/interface/initialize/loading.py +7 -6
  299. langflow/interface/listing.py +3 -25
  300. langflow/interface/run.py +1 -1
  301. langflow/interface/utils.py +3 -111
  302. langflow/io/__init__.py +2 -2
  303. langflow/io/schema.py +11 -302
  304. langflow/load/__init__.py +4 -2
  305. langflow/load/utils.py +2 -96
  306. langflow/logging/__init__.py +2 -1
  307. langflow/logging/setup.py +1 -1
  308. langflow/main.py +8 -5
  309. langflow/memory.py +12 -6
  310. langflow/middleware.py +1 -1
  311. langflow/processing/process.py +7 -7
  312. langflow/schema/__init__.py +22 -5
  313. langflow/schema/artifact.py +1 -1
  314. langflow/schema/data.py +5 -303
  315. langflow/schema/dataframe.py +2 -205
  316. langflow/schema/graph.py +4 -45
  317. langflow/schema/image.py +2 -67
  318. langflow/schema/message.py +6 -470
  319. langflow/schema/playground_events.py +5 -6
  320. langflow/schema/schema.py +24 -117
  321. langflow/serialization/constants.py +3 -2
  322. langflow/serialization/serialization.py +1 -1
  323. langflow/server.py +1 -2
  324. langflow/services/__init__.py +1 -2
  325. langflow/services/auth/mcp_encryption.py +1 -1
  326. langflow/services/auth/service.py +1 -1
  327. langflow/services/auth/utils.py +5 -5
  328. langflow/services/cache/disk.py +2 -2
  329. langflow/services/cache/factory.py +2 -2
  330. langflow/services/cache/service.py +2 -2
  331. langflow/services/cache/utils.py +0 -11
  332. langflow/services/database/factory.py +1 -1
  333. langflow/services/database/models/flow/model.py +1 -1
  334. langflow/services/database/models/message/crud.py +2 -1
  335. langflow/services/database/models/transactions/crud.py +1 -1
  336. langflow/services/database/models/user/crud.py +1 -1
  337. langflow/services/database/service.py +2 -2
  338. langflow/services/database/utils.py +1 -2
  339. langflow/services/deps.py +12 -17
  340. langflow/services/enhanced_manager.py +71 -0
  341. langflow/services/factory.py +14 -7
  342. langflow/services/flow/flow_runner.py +4 -4
  343. langflow/services/job_queue/service.py +2 -1
  344. langflow/services/manager.py +14 -130
  345. langflow/services/schema.py +0 -1
  346. langflow/services/session/service.py +3 -2
  347. langflow/services/settings/__init__.py +0 -3
  348. langflow/services/settings/base.py +16 -549
  349. langflow/services/settings/factory.py +2 -21
  350. langflow/services/settings/feature_flags.py +2 -11
  351. langflow/services/settings/service.py +2 -31
  352. langflow/services/shared_component_cache/factory.py +1 -1
  353. langflow/services/socket/service.py +1 -1
  354. langflow/services/socket/utils.py +1 -8
  355. langflow/services/state/factory.py +1 -1
  356. langflow/services/state/service.py +3 -2
  357. langflow/services/storage/factory.py +2 -2
  358. langflow/services/storage/local.py +1 -2
  359. langflow/services/storage/s3.py +1 -2
  360. langflow/services/storage/service.py +2 -1
  361. langflow/services/store/factory.py +1 -1
  362. langflow/services/store/service.py +2 -2
  363. langflow/services/store/utils.py +1 -2
  364. langflow/services/task/service.py +2 -1
  365. langflow/services/task/temp_flow_cleanup.py +1 -1
  366. langflow/services/telemetry/factory.py +1 -1
  367. langflow/services/telemetry/service.py +2 -3
  368. langflow/services/tracing/arize_phoenix.py +3 -3
  369. langflow/services/tracing/base.py +1 -1
  370. langflow/services/tracing/factory.py +1 -1
  371. langflow/services/tracing/langfuse.py +2 -2
  372. langflow/services/tracing/langsmith.py +2 -2
  373. langflow/services/tracing/langwatch.py +4 -4
  374. langflow/services/tracing/opik.py +2 -2
  375. langflow/services/tracing/service.py +17 -11
  376. langflow/services/tracing/traceloop.py +2 -2
  377. langflow/services/tracing/utils.py +1 -1
  378. langflow/services/utils.py +54 -9
  379. langflow/services/variable/factory.py +1 -1
  380. langflow/services/variable/kubernetes.py +2 -3
  381. langflow/services/variable/kubernetes_secrets.py +1 -2
  382. langflow/services/variable/service.py +2 -3
  383. langflow/template/__init__.py +2 -9
  384. langflow/template/field/__init__.py +3 -0
  385. langflow/template/field/base.py +2 -256
  386. langflow/template/frontend_node.py +3 -0
  387. langflow/template/utils.py +2 -216
  388. langflow/utils/constants.py +28 -204
  389. langflow/utils/lazy_load.py +3 -14
  390. langflow/utils/schemas.py +2 -3
  391. langflow/utils/template_validation.py +2 -2
  392. langflow/utils/util.py +59 -479
  393. langflow/utils/validate.py +2 -488
  394. langflow/utils/voice_utils.py +1 -2
  395. langflow/worker.py +1 -1
  396. {langflow_base_nightly-0.5.1.dev3.dist-info → langflow_base_nightly-0.5.1.dev4.dist-info}/METADATA +2 -1
  397. langflow_base_nightly-0.5.1.dev4.dist-info/RECORD +633 -0
  398. langflow/base/agents/agent.py +0 -267
  399. langflow/base/agents/callback.py +0 -130
  400. langflow/base/agents/context.py +0 -109
  401. langflow/base/agents/crewai/__init__.py +0 -0
  402. langflow/base/agents/crewai/crew.py +0 -231
  403. langflow/base/agents/crewai/tasks.py +0 -12
  404. langflow/base/agents/default_prompts.py +0 -23
  405. langflow/base/agents/errors.py +0 -15
  406. langflow/base/agents/events.py +0 -346
  407. langflow/base/agents/utils.py +0 -205
  408. langflow/base/astra_assistants/__init__.py +0 -0
  409. langflow/base/astra_assistants/util.py +0 -171
  410. langflow/base/chains/__init__.py +0 -0
  411. langflow/base/chains/model.py +0 -19
  412. langflow/base/composio/__init__.py +0 -0
  413. langflow/base/composio/composio_base.py +0 -1297
  414. langflow/base/compressors/__init__.py +0 -0
  415. langflow/base/compressors/model.py +0 -60
  416. langflow/base/constants.py +0 -46
  417. langflow/base/curl/__init__.py +0 -0
  418. langflow/base/curl/parse.py +0 -188
  419. langflow/base/data/base_file.py +0 -685
  420. langflow/base/data/docling_utils.py +0 -245
  421. langflow/base/document_transformers/__init__.py +0 -0
  422. langflow/base/document_transformers/model.py +0 -43
  423. langflow/base/embeddings/aiml_embeddings.py +0 -62
  424. langflow/base/embeddings/model.py +0 -26
  425. langflow/base/flow_processing/__init__.py +0 -0
  426. langflow/base/flow_processing/utils.py +0 -86
  427. langflow/base/huggingface/__init__.py +0 -0
  428. langflow/base/huggingface/model_bridge.py +0 -133
  429. langflow/base/langchain_utilities/__init__.py +0 -0
  430. langflow/base/langchain_utilities/model.py +0 -35
  431. langflow/base/langchain_utilities/spider_constants.py +0 -1
  432. langflow/base/langwatch/__init__.py +0 -0
  433. langflow/base/langwatch/utils.py +0 -18
  434. langflow/base/mcp/__init__.py +0 -0
  435. langflow/base/mcp/constants.py +0 -2
  436. langflow/base/mcp/util.py +0 -1524
  437. langflow/base/memory/memory.py +0 -49
  438. langflow/base/memory/model.py +0 -38
  439. langflow/base/models/aiml_constants.py +0 -51
  440. langflow/base/models/anthropic_constants.py +0 -47
  441. langflow/base/models/aws_constants.py +0 -151
  442. langflow/base/models/chat_result.py +0 -76
  443. langflow/base/models/google_generative_ai_constants.py +0 -70
  444. langflow/base/models/groq_constants.py +0 -134
  445. langflow/base/models/model.py +0 -375
  446. langflow/base/models/model_input_constants.py +0 -299
  447. langflow/base/models/model_metadata.py +0 -41
  448. langflow/base/models/model_utils.py +0 -8
  449. langflow/base/models/novita_constants.py +0 -35
  450. langflow/base/models/ollama_constants.py +0 -49
  451. langflow/base/models/sambanova_constants.py +0 -18
  452. langflow/base/processing/__init__.py +0 -0
  453. langflow/base/prompts/utils.py +0 -61
  454. langflow/base/textsplitters/model.py +0 -28
  455. langflow/base/tools/base.py +0 -26
  456. langflow/base/tools/component_tool.py +0 -324
  457. langflow/base/tools/constants.py +0 -49
  458. langflow/base/tools/flow_tool.py +0 -131
  459. langflow/base/tools/run_flow.py +0 -227
  460. langflow/base/vectorstores/model.py +0 -193
  461. langflow/base/vectorstores/utils.py +0 -22
  462. langflow/base/vectorstores/vector_store_connection_decorator.py +0 -52
  463. langflow/components/FAISS/__init__.py +0 -34
  464. langflow/components/FAISS/faiss.py +0 -111
  465. langflow/components/Notion/__init__.py +0 -19
  466. langflow/components/Notion/add_content_to_page.py +0 -269
  467. langflow/components/Notion/create_page.py +0 -94
  468. langflow/components/Notion/list_database_properties.py +0 -68
  469. langflow/components/Notion/list_pages.py +0 -122
  470. langflow/components/Notion/list_users.py +0 -77
  471. langflow/components/Notion/page_content_viewer.py +0 -93
  472. langflow/components/Notion/search.py +0 -111
  473. langflow/components/Notion/update_page_property.py +0 -114
  474. langflow/components/_importing.py +0 -37
  475. langflow/components/agentql/__init__.py +0 -3
  476. langflow/components/agentql/agentql_api.py +0 -151
  477. langflow/components/agents/__init__.py +0 -4
  478. langflow/components/agents/agent.py +0 -554
  479. langflow/components/agents/mcp_component.py +0 -501
  480. langflow/components/aiml/__init__.py +0 -37
  481. langflow/components/aiml/aiml.py +0 -112
  482. langflow/components/aiml/aiml_embeddings.py +0 -37
  483. langflow/components/amazon/__init__.py +0 -36
  484. langflow/components/amazon/amazon_bedrock_embedding.py +0 -109
  485. langflow/components/amazon/amazon_bedrock_model.py +0 -124
  486. langflow/components/amazon/s3_bucket_uploader.py +0 -211
  487. langflow/components/anthropic/__init__.py +0 -34
  488. langflow/components/anthropic/anthropic.py +0 -187
  489. langflow/components/apify/__init__.py +0 -5
  490. langflow/components/apify/apify_actor.py +0 -325
  491. langflow/components/arxiv/__init__.py +0 -3
  492. langflow/components/arxiv/arxiv.py +0 -163
  493. langflow/components/assemblyai/__init__.py +0 -46
  494. langflow/components/assemblyai/assemblyai_get_subtitles.py +0 -83
  495. langflow/components/assemblyai/assemblyai_lemur.py +0 -183
  496. langflow/components/assemblyai/assemblyai_list_transcripts.py +0 -95
  497. langflow/components/assemblyai/assemblyai_poll_transcript.py +0 -72
  498. langflow/components/assemblyai/assemblyai_start_transcript.py +0 -188
  499. langflow/components/azure/__init__.py +0 -37
  500. langflow/components/azure/azure_openai.py +0 -95
  501. langflow/components/azure/azure_openai_embeddings.py +0 -83
  502. langflow/components/baidu/__init__.py +0 -32
  503. langflow/components/baidu/baidu_qianfan_chat.py +0 -113
  504. langflow/components/bing/__init__.py +0 -3
  505. langflow/components/bing/bing_search_api.py +0 -61
  506. langflow/components/cassandra/__init__.py +0 -40
  507. langflow/components/cassandra/cassandra.py +0 -264
  508. langflow/components/cassandra/cassandra_chat.py +0 -92
  509. langflow/components/cassandra/cassandra_graph.py +0 -238
  510. langflow/components/chains/__init__.py +0 -0
  511. langflow/components/chroma/__init__.py +0 -34
  512. langflow/components/chroma/chroma.py +0 -167
  513. langflow/components/cleanlab/__init__.py +0 -40
  514. langflow/components/cleanlab/cleanlab_evaluator.py +0 -157
  515. langflow/components/cleanlab/cleanlab_rag_evaluator.py +0 -254
  516. langflow/components/cleanlab/cleanlab_remediator.py +0 -131
  517. langflow/components/clickhouse/__init__.py +0 -34
  518. langflow/components/clickhouse/clickhouse.py +0 -135
  519. langflow/components/cloudflare/__init__.py +0 -32
  520. langflow/components/cloudflare/cloudflare.py +0 -81
  521. langflow/components/cohere/__init__.py +0 -40
  522. langflow/components/cohere/cohere_embeddings.py +0 -81
  523. langflow/components/cohere/cohere_models.py +0 -46
  524. langflow/components/cohere/cohere_rerank.py +0 -51
  525. langflow/components/composio/__init__.py +0 -73
  526. langflow/components/composio/composio_api.py +0 -268
  527. langflow/components/composio/dropbox_compnent.py +0 -11
  528. langflow/components/composio/github_composio.py +0 -11
  529. langflow/components/composio/gmail_composio.py +0 -38
  530. langflow/components/composio/googlecalendar_composio.py +0 -11
  531. langflow/components/composio/googlemeet_composio.py +0 -11
  532. langflow/components/composio/googletasks_composio.py +0 -8
  533. langflow/components/composio/linear_composio.py +0 -11
  534. langflow/components/composio/outlook_composio.py +0 -11
  535. langflow/components/composio/reddit_composio.py +0 -11
  536. langflow/components/composio/slack_composio.py +0 -11
  537. langflow/components/composio/slackbot_composio.py +0 -11
  538. langflow/components/composio/supabase_composio.py +0 -11
  539. langflow/components/composio/todoist_composio.py +0 -11
  540. langflow/components/composio/youtube_composio.py +0 -11
  541. langflow/components/confluence/__init__.py +0 -3
  542. langflow/components/confluence/confluence.py +0 -84
  543. langflow/components/couchbase/__init__.py +0 -34
  544. langflow/components/couchbase/couchbase.py +0 -102
  545. langflow/components/crewai/__init__.py +0 -49
  546. langflow/components/crewai/crewai.py +0 -107
  547. langflow/components/crewai/hierarchical_crew.py +0 -46
  548. langflow/components/crewai/hierarchical_task.py +0 -44
  549. langflow/components/crewai/sequential_crew.py +0 -52
  550. langflow/components/crewai/sequential_task.py +0 -73
  551. langflow/components/crewai/sequential_task_agent.py +0 -143
  552. langflow/components/custom_component/__init__.py +0 -34
  553. langflow/components/custom_component/custom_component.py +0 -31
  554. langflow/components/data/__init__.py +0 -25
  555. langflow/components/data/api_request.py +0 -545
  556. langflow/components/data/csv_to_data.py +0 -95
  557. langflow/components/data/directory.py +0 -113
  558. langflow/components/data/file.py +0 -586
  559. langflow/components/data/json_to_data.py +0 -98
  560. langflow/components/data/news_search.py +0 -164
  561. langflow/components/data/rss.py +0 -69
  562. langflow/components/data/sql_executor.py +0 -99
  563. langflow/components/data/url.py +0 -299
  564. langflow/components/data/web_search.py +0 -112
  565. langflow/components/data/webhook.py +0 -56
  566. langflow/components/datastax/__init__.py +0 -70
  567. langflow/components/datastax/astra_assistant_manager.py +0 -306
  568. langflow/components/datastax/astra_db.py +0 -69
  569. langflow/components/datastax/astra_vectorize.py +0 -124
  570. langflow/components/datastax/astradb_cql.py +0 -314
  571. langflow/components/datastax/astradb_graph.py +0 -319
  572. langflow/components/datastax/astradb_tool.py +0 -414
  573. langflow/components/datastax/astradb_vectorstore.py +0 -1285
  574. langflow/components/datastax/create_assistant.py +0 -58
  575. langflow/components/datastax/create_thread.py +0 -32
  576. langflow/components/datastax/dotenv.py +0 -35
  577. langflow/components/datastax/get_assistant.py +0 -37
  578. langflow/components/datastax/getenvvar.py +0 -30
  579. langflow/components/datastax/graph_rag.py +0 -141
  580. langflow/components/datastax/hcd.py +0 -314
  581. langflow/components/datastax/list_assistants.py +0 -25
  582. langflow/components/datastax/run.py +0 -89
  583. langflow/components/deactivated/__init__.py +0 -19
  584. langflow/components/deactivated/amazon_kendra.py +0 -66
  585. langflow/components/deactivated/chat_litellm_model.py +0 -158
  586. langflow/components/deactivated/code_block_extractor.py +0 -26
  587. langflow/components/deactivated/documents_to_data.py +0 -22
  588. langflow/components/deactivated/embed.py +0 -16
  589. langflow/components/deactivated/extract_key_from_data.py +0 -46
  590. langflow/components/deactivated/json_document_builder.py +0 -59
  591. langflow/components/deactivated/list_flows.py +0 -20
  592. langflow/components/deactivated/mcp_sse.py +0 -61
  593. langflow/components/deactivated/mcp_stdio.py +0 -62
  594. langflow/components/deactivated/merge_data.py +0 -93
  595. langflow/components/deactivated/message.py +0 -37
  596. langflow/components/deactivated/metal.py +0 -54
  597. langflow/components/deactivated/multi_query.py +0 -59
  598. langflow/components/deactivated/retriever.py +0 -43
  599. langflow/components/deactivated/selective_passthrough.py +0 -77
  600. langflow/components/deactivated/should_run_next.py +0 -40
  601. langflow/components/deactivated/split_text.py +0 -63
  602. langflow/components/deactivated/store_message.py +0 -24
  603. langflow/components/deactivated/sub_flow.py +0 -124
  604. langflow/components/deactivated/vectara_self_query.py +0 -76
  605. langflow/components/deactivated/vector_store.py +0 -24
  606. langflow/components/deepseek/__init__.py +0 -34
  607. langflow/components/deepseek/deepseek.py +0 -136
  608. langflow/components/docling/__init__.py +0 -43
  609. langflow/components/docling/chunk_docling_document.py +0 -186
  610. langflow/components/docling/docling_inline.py +0 -235
  611. langflow/components/docling/docling_remote.py +0 -193
  612. langflow/components/docling/export_docling_document.py +0 -117
  613. langflow/components/documentloaders/__init__.py +0 -0
  614. langflow/components/duckduckgo/__init__.py +0 -3
  615. langflow/components/duckduckgo/duck_duck_go_search_run.py +0 -92
  616. langflow/components/elastic/__init__.py +0 -37
  617. langflow/components/elastic/elasticsearch.py +0 -267
  618. langflow/components/elastic/opensearch.py +0 -243
  619. langflow/components/embeddings/__init__.py +0 -37
  620. langflow/components/embeddings/similarity.py +0 -76
  621. langflow/components/embeddings/text_embedder.py +0 -64
  622. langflow/components/exa/__init__.py +0 -3
  623. langflow/components/exa/exa_search.py +0 -68
  624. langflow/components/firecrawl/__init__.py +0 -43
  625. langflow/components/firecrawl/firecrawl_crawl_api.py +0 -88
  626. langflow/components/firecrawl/firecrawl_extract_api.py +0 -136
  627. langflow/components/firecrawl/firecrawl_map_api.py +0 -89
  628. langflow/components/firecrawl/firecrawl_scrape_api.py +0 -73
  629. langflow/components/git/__init__.py +0 -4
  630. langflow/components/git/git.py +0 -262
  631. langflow/components/git/gitextractor.py +0 -196
  632. langflow/components/glean/__init__.py +0 -3
  633. langflow/components/glean/glean_search_api.py +0 -173
  634. langflow/components/google/__init__.py +0 -17
  635. langflow/components/google/gmail.py +0 -192
  636. langflow/components/google/google_bq_sql_executor.py +0 -157
  637. langflow/components/google/google_drive.py +0 -92
  638. langflow/components/google/google_drive_search.py +0 -152
  639. langflow/components/google/google_generative_ai.py +0 -147
  640. langflow/components/google/google_generative_ai_embeddings.py +0 -141
  641. langflow/components/google/google_oauth_token.py +0 -89
  642. langflow/components/google/google_search_api_core.py +0 -68
  643. langflow/components/google/google_serper_api_core.py +0 -74
  644. langflow/components/groq/__init__.py +0 -34
  645. langflow/components/groq/groq.py +0 -140
  646. langflow/components/helpers/__init__.py +0 -52
  647. langflow/components/helpers/calculator_core.py +0 -89
  648. langflow/components/helpers/create_list.py +0 -40
  649. langflow/components/helpers/current_date.py +0 -42
  650. langflow/components/helpers/id_generator.py +0 -42
  651. langflow/components/helpers/memory.py +0 -251
  652. langflow/components/helpers/output_parser.py +0 -45
  653. langflow/components/helpers/store_message.py +0 -90
  654. langflow/components/homeassistant/__init__.py +0 -7
  655. langflow/components/homeassistant/home_assistant_control.py +0 -152
  656. langflow/components/homeassistant/list_home_assistant_states.py +0 -137
  657. langflow/components/huggingface/__init__.py +0 -37
  658. langflow/components/huggingface/huggingface.py +0 -197
  659. langflow/components/huggingface/huggingface_inference_api.py +0 -106
  660. langflow/components/ibm/__init__.py +0 -34
  661. langflow/components/ibm/watsonx.py +0 -203
  662. langflow/components/ibm/watsonx_embeddings.py +0 -135
  663. langflow/components/icosacomputing/__init__.py +0 -5
  664. langflow/components/icosacomputing/combinatorial_reasoner.py +0 -84
  665. langflow/components/input_output/__init__.py +0 -38
  666. langflow/components/input_output/chat.py +0 -120
  667. langflow/components/input_output/chat_output.py +0 -200
  668. langflow/components/input_output/text.py +0 -27
  669. langflow/components/input_output/text_output.py +0 -29
  670. langflow/components/jigsawstack/__init__.py +0 -23
  671. langflow/components/jigsawstack/ai_scrape.py +0 -126
  672. langflow/components/jigsawstack/ai_web_search.py +0 -136
  673. langflow/components/jigsawstack/file_read.py +0 -115
  674. langflow/components/jigsawstack/file_upload.py +0 -94
  675. langflow/components/jigsawstack/image_generation.py +0 -205
  676. langflow/components/jigsawstack/nsfw.py +0 -60
  677. langflow/components/jigsawstack/object_detection.py +0 -124
  678. langflow/components/jigsawstack/sentiment.py +0 -112
  679. langflow/components/jigsawstack/text_to_sql.py +0 -90
  680. langflow/components/jigsawstack/text_translate.py +0 -77
  681. langflow/components/jigsawstack/vocr.py +0 -107
  682. langflow/components/langchain_utilities/__init__.py +0 -109
  683. langflow/components/langchain_utilities/character.py +0 -53
  684. langflow/components/langchain_utilities/conversation.py +0 -52
  685. langflow/components/langchain_utilities/csv_agent.py +0 -107
  686. langflow/components/langchain_utilities/fake_embeddings.py +0 -26
  687. langflow/components/langchain_utilities/html_link_extractor.py +0 -35
  688. langflow/components/langchain_utilities/json_agent.py +0 -45
  689. langflow/components/langchain_utilities/langchain_hub.py +0 -126
  690. langflow/components/langchain_utilities/language_recursive.py +0 -49
  691. langflow/components/langchain_utilities/language_semantic.py +0 -138
  692. langflow/components/langchain_utilities/llm_checker.py +0 -39
  693. langflow/components/langchain_utilities/llm_math.py +0 -42
  694. langflow/components/langchain_utilities/natural_language.py +0 -61
  695. langflow/components/langchain_utilities/openai_tools.py +0 -53
  696. langflow/components/langchain_utilities/openapi.py +0 -48
  697. langflow/components/langchain_utilities/recursive_character.py +0 -60
  698. langflow/components/langchain_utilities/retrieval_qa.py +0 -83
  699. langflow/components/langchain_utilities/runnable_executor.py +0 -137
  700. langflow/components/langchain_utilities/self_query.py +0 -80
  701. langflow/components/langchain_utilities/spider.py +0 -142
  702. langflow/components/langchain_utilities/sql.py +0 -40
  703. langflow/components/langchain_utilities/sql_database.py +0 -35
  704. langflow/components/langchain_utilities/sql_generator.py +0 -78
  705. langflow/components/langchain_utilities/tool_calling.py +0 -59
  706. langflow/components/langchain_utilities/vector_store_info.py +0 -49
  707. langflow/components/langchain_utilities/vector_store_router.py +0 -33
  708. langflow/components/langchain_utilities/xml_agent.py +0 -71
  709. langflow/components/langwatch/__init__.py +0 -3
  710. langflow/components/langwatch/langwatch.py +0 -278
  711. langflow/components/link_extractors/__init__.py +0 -0
  712. langflow/components/lmstudio/__init__.py +0 -34
  713. langflow/components/lmstudio/lmstudioembeddings.py +0 -89
  714. langflow/components/lmstudio/lmstudiomodel.py +0 -129
  715. langflow/components/logic/__init__.py +0 -52
  716. langflow/components/logic/conditional_router.py +0 -171
  717. langflow/components/logic/data_conditional_router.py +0 -125
  718. langflow/components/logic/flow_tool.py +0 -110
  719. langflow/components/logic/listen.py +0 -29
  720. langflow/components/logic/loop.py +0 -125
  721. langflow/components/logic/notify.py +0 -88
  722. langflow/components/logic/pass_message.py +0 -35
  723. langflow/components/logic/run_flow.py +0 -71
  724. langflow/components/logic/sub_flow.py +0 -114
  725. langflow/components/maritalk/__init__.py +0 -32
  726. langflow/components/maritalk/maritalk.py +0 -52
  727. langflow/components/mem0/__init__.py +0 -3
  728. langflow/components/mem0/mem0_chat_memory.py +0 -136
  729. langflow/components/milvus/__init__.py +0 -34
  730. langflow/components/milvus/milvus.py +0 -115
  731. langflow/components/mistral/__init__.py +0 -37
  732. langflow/components/mistral/mistral.py +0 -114
  733. langflow/components/mistral/mistral_embeddings.py +0 -58
  734. langflow/components/models/__init__.py +0 -34
  735. langflow/components/models/embedding_model.py +0 -114
  736. langflow/components/models/language_model.py +0 -144
  737. langflow/components/mongodb/__init__.py +0 -34
  738. langflow/components/mongodb/mongodb_atlas.py +0 -213
  739. langflow/components/needle/__init__.py +0 -3
  740. langflow/components/needle/needle.py +0 -104
  741. langflow/components/notdiamond/__init__.py +0 -36
  742. langflow/components/notdiamond/notdiamond.py +0 -228
  743. langflow/components/novita/__init__.py +0 -32
  744. langflow/components/novita/novita.py +0 -130
  745. langflow/components/nvidia/__init__.py +0 -57
  746. langflow/components/nvidia/nvidia.py +0 -157
  747. langflow/components/nvidia/nvidia_embedding.py +0 -77
  748. langflow/components/nvidia/nvidia_ingest.py +0 -317
  749. langflow/components/nvidia/nvidia_rerank.py +0 -63
  750. langflow/components/nvidia/system_assist.py +0 -65
  751. langflow/components/olivya/__init__.py +0 -3
  752. langflow/components/olivya/olivya.py +0 -116
  753. langflow/components/ollama/__init__.py +0 -37
  754. langflow/components/ollama/ollama.py +0 -330
  755. langflow/components/ollama/ollama_embeddings.py +0 -106
  756. langflow/components/openai/__init__.py +0 -37
  757. langflow/components/openai/openai.py +0 -100
  758. langflow/components/openai/openai_chat_model.py +0 -158
  759. langflow/components/openrouter/__init__.py +0 -32
  760. langflow/components/openrouter/openrouter.py +0 -202
  761. langflow/components/output_parsers/__init__.py +0 -0
  762. langflow/components/perplexity/__init__.py +0 -34
  763. langflow/components/perplexity/perplexity.py +0 -75
  764. langflow/components/pgvector/__init__.py +0 -34
  765. langflow/components/pgvector/pgvector.py +0 -72
  766. langflow/components/pinecone/__init__.py +0 -34
  767. langflow/components/pinecone/pinecone.py +0 -134
  768. langflow/components/processing/alter_metadata.py +0 -108
  769. langflow/components/processing/batch_run.py +0 -205
  770. langflow/components/processing/combine_text.py +0 -39
  771. langflow/components/processing/create_data.py +0 -110
  772. langflow/components/processing/data_operations.py +0 -438
  773. langflow/components/processing/data_to_dataframe.py +0 -70
  774. langflow/components/processing/dataframe_operations.py +0 -321
  775. langflow/components/processing/extract_key.py +0 -53
  776. langflow/components/processing/filter_data.py +0 -42
  777. langflow/components/processing/filter_data_values.py +0 -88
  778. langflow/components/processing/json_cleaner.py +0 -103
  779. langflow/components/processing/lambda_filter.py +0 -154
  780. langflow/components/processing/llm_router.py +0 -499
  781. langflow/components/processing/merge_data.py +0 -90
  782. langflow/components/processing/message_to_data.py +0 -36
  783. langflow/components/processing/parse_data.py +0 -70
  784. langflow/components/processing/parse_dataframe.py +0 -68
  785. langflow/components/processing/parse_json_data.py +0 -90
  786. langflow/components/processing/parser.py +0 -143
  787. langflow/components/processing/prompt.py +0 -67
  788. langflow/components/processing/python_repl_core.py +0 -98
  789. langflow/components/processing/regex.py +0 -82
  790. langflow/components/processing/save_file.py +0 -208
  791. langflow/components/processing/select_data.py +0 -48
  792. langflow/components/processing/split_text.py +0 -141
  793. langflow/components/processing/structured_output.py +0 -202
  794. langflow/components/processing/update_data.py +0 -160
  795. langflow/components/prototypes/__init__.py +0 -34
  796. langflow/components/prototypes/python_function.py +0 -73
  797. langflow/components/qdrant/__init__.py +0 -34
  798. langflow/components/qdrant/qdrant.py +0 -109
  799. langflow/components/redis/__init__.py +0 -37
  800. langflow/components/redis/redis.py +0 -89
  801. langflow/components/redis/redis_chat.py +0 -43
  802. langflow/components/sambanova/__init__.py +0 -32
  803. langflow/components/sambanova/sambanova.py +0 -84
  804. langflow/components/scrapegraph/__init__.py +0 -40
  805. langflow/components/scrapegraph/scrapegraph_markdownify_api.py +0 -64
  806. langflow/components/scrapegraph/scrapegraph_search_api.py +0 -64
  807. langflow/components/scrapegraph/scrapegraph_smart_scraper_api.py +0 -71
  808. langflow/components/searchapi/__init__.py +0 -36
  809. langflow/components/searchapi/search.py +0 -79
  810. langflow/components/serpapi/__init__.py +0 -3
  811. langflow/components/serpapi/serp.py +0 -115
  812. langflow/components/serper/__init__.py +0 -3
  813. langflow/components/serper/google_serper_api_core.py +0 -74
  814. langflow/components/supabase/__init__.py +0 -37
  815. langflow/components/supabase/supabase.py +0 -76
  816. langflow/components/tavily/__init__.py +0 -4
  817. langflow/components/tavily/tavily_extract.py +0 -117
  818. langflow/components/tavily/tavily_search.py +0 -212
  819. langflow/components/textsplitters/__init__.py +0 -0
  820. langflow/components/toolkits/__init__.py +0 -0
  821. langflow/components/tools/__init__.py +0 -72
  822. langflow/components/tools/calculator.py +0 -103
  823. langflow/components/tools/google_search_api.py +0 -45
  824. langflow/components/tools/google_serper_api.py +0 -115
  825. langflow/components/tools/python_code_structured_tool.py +0 -327
  826. langflow/components/tools/python_repl.py +0 -97
  827. langflow/components/tools/search_api.py +0 -87
  828. langflow/components/tools/searxng.py +0 -145
  829. langflow/components/tools/serp_api.py +0 -119
  830. langflow/components/tools/tavily_search_tool.py +0 -344
  831. langflow/components/tools/wikidata_api.py +0 -102
  832. langflow/components/tools/wikipedia_api.py +0 -49
  833. langflow/components/tools/yahoo_finance.py +0 -124
  834. langflow/components/twelvelabs/__init__.py +0 -52
  835. langflow/components/twelvelabs/convert_astra_results.py +0 -84
  836. langflow/components/twelvelabs/pegasus_index.py +0 -311
  837. langflow/components/twelvelabs/split_video.py +0 -291
  838. langflow/components/twelvelabs/text_embeddings.py +0 -57
  839. langflow/components/twelvelabs/twelvelabs_pegasus.py +0 -408
  840. langflow/components/twelvelabs/video_embeddings.py +0 -100
  841. langflow/components/twelvelabs/video_file.py +0 -179
  842. langflow/components/unstructured/__init__.py +0 -3
  843. langflow/components/unstructured/unstructured.py +0 -121
  844. langflow/components/upstash/__init__.py +0 -34
  845. langflow/components/upstash/upstash.py +0 -124
  846. langflow/components/vectara/__init__.py +0 -37
  847. langflow/components/vectara/vectara.py +0 -97
  848. langflow/components/vectara/vectara_rag.py +0 -164
  849. langflow/components/vectorstores/__init__.py +0 -34
  850. langflow/components/vectorstores/local_db.py +0 -261
  851. langflow/components/vertexai/__init__.py +0 -37
  852. langflow/components/vertexai/vertexai.py +0 -71
  853. langflow/components/vertexai/vertexai_embeddings.py +0 -67
  854. langflow/components/weaviate/__init__.py +0 -34
  855. langflow/components/weaviate/weaviate.py +0 -89
  856. langflow/components/wikipedia/__init__.py +0 -4
  857. langflow/components/wikipedia/wikidata.py +0 -86
  858. langflow/components/wikipedia/wikipedia.py +0 -53
  859. langflow/components/wolframalpha/__init__.py +0 -3
  860. langflow/components/wolframalpha/wolfram_alpha_api.py +0 -54
  861. langflow/components/xai/__init__.py +0 -32
  862. langflow/components/xai/xai.py +0 -167
  863. langflow/components/yahoosearch/__init__.py +0 -3
  864. langflow/components/yahoosearch/yahoo.py +0 -137
  865. langflow/components/youtube/__init__.py +0 -52
  866. langflow/components/youtube/channel.py +0 -227
  867. langflow/components/youtube/comments.py +0 -231
  868. langflow/components/youtube/playlist.py +0 -33
  869. langflow/components/youtube/search.py +0 -120
  870. langflow/components/youtube/trending.py +0 -285
  871. langflow/components/youtube/video_details.py +0 -263
  872. langflow/components/youtube/youtube_transcripts.py +0 -118
  873. langflow/components/zep/__init__.py +0 -3
  874. langflow/components/zep/zep.py +0 -44
  875. langflow/custom/attributes.py +0 -86
  876. langflow/custom/code_parser/__init__.py +0 -3
  877. langflow/custom/code_parser/code_parser.py +0 -361
  878. langflow/custom/custom_component/base_component.py +0 -118
  879. langflow/custom/dependency_analyzer.py +0 -165
  880. langflow/custom/directory_reader/__init__.py +0 -3
  881. langflow/custom/directory_reader/directory_reader.py +0 -359
  882. langflow/custom/directory_reader/utils.py +0 -171
  883. langflow/custom/eval.py +0 -12
  884. langflow/custom/schema.py +0 -32
  885. langflow/custom/tree_visitor.py +0 -21
  886. langflow/frontend/assets/lazyIconImports-Ci-S9xBA.js +0 -2
  887. langflow/graph/edge/__init__.py +0 -0
  888. langflow/graph/edge/base.py +0 -277
  889. langflow/graph/edge/schema.py +0 -119
  890. langflow/graph/edge/utils.py +0 -0
  891. langflow/graph/graph/__init__.py +0 -0
  892. langflow/graph/graph/ascii.py +0 -202
  893. langflow/graph/graph/base.py +0 -2185
  894. langflow/graph/graph/constants.py +0 -58
  895. langflow/graph/graph/runnable_vertices_manager.py +0 -133
  896. langflow/graph/graph/schema.py +0 -53
  897. langflow/graph/graph/state_model.py +0 -66
  898. langflow/graph/graph/utils.py +0 -1024
  899. langflow/graph/schema.py +0 -75
  900. langflow/graph/state/__init__.py +0 -0
  901. langflow/graph/state/model.py +0 -237
  902. langflow/graph/utils.py +0 -229
  903. langflow/graph/vertex/__init__.py +0 -0
  904. langflow/graph/vertex/base.py +0 -811
  905. langflow/graph/vertex/constants.py +0 -0
  906. langflow/graph/vertex/exceptions.py +0 -4
  907. langflow/graph/vertex/param_handler.py +0 -255
  908. langflow/graph/vertex/schema.py +0 -26
  909. langflow/graph/vertex/utils.py +0 -19
  910. langflow/graph/vertex/vertex_types.py +0 -489
  911. langflow/legacy_custom/__init__.py +0 -0
  912. langflow/legacy_custom/customs.py +0 -16
  913. langflow/load/load.py +0 -250
  914. langflow/logging/logger.py +0 -369
  915. langflow/processing/utils.py +0 -25
  916. langflow/schema/openai_responses_schemas.py +0 -74
  917. langflow/schema/serialize.py +0 -13
  918. langflow/services/chat/config.py +0 -2
  919. langflow/services/settings/auth.py +0 -130
  920. langflow/services/settings/constants.py +0 -31
  921. langflow/services/settings/manager.py +0 -49
  922. langflow/services/settings/utils.py +0 -40
  923. langflow/template/field/prompt.py +0 -2
  924. langflow/template/frontend_node/__init__.py +0 -6
  925. langflow/template/frontend_node/base.py +0 -212
  926. langflow/template/frontend_node/constants.py +0 -65
  927. langflow/template/frontend_node/custom_components.py +0 -97
  928. langflow/template/template/__init__.py +0 -0
  929. langflow/template/template/base.py +0 -99
  930. langflow/utils/async_helpers.py +0 -42
  931. langflow/utils/concurrency.py +0 -60
  932. langflow/utils/util_strings.py +0 -56
  933. langflow_base_nightly-0.5.1.dev3.dist-info/RECORD +0 -1159
  934. {langflow_base_nightly-0.5.1.dev3.dist-info → langflow_base_nightly-0.5.1.dev4.dist-info}/WHEEL +0 -0
  935. {langflow_base_nightly-0.5.1.dev3.dist-info → langflow_base_nightly-0.5.1.dev4.dist-info}/entry_points.txt +0 -0
@@ -1,1297 +0,0 @@
1
- import copy
2
- import re
3
- from typing import Any
4
-
5
- from composio import Composio
6
- from composio_langchain import LangchainProvider
7
- from langchain_core.tools import Tool
8
-
9
- from langflow.base.mcp.util import create_input_schema_from_json_schema
10
- from langflow.custom.custom_component.component import Component
11
- from langflow.inputs.inputs import (
12
- AuthInput,
13
- FileInput,
14
- InputTypes,
15
- MessageTextInput,
16
- SecretStrInput,
17
- SortableListInput,
18
- )
19
- from langflow.io import Output
20
- from langflow.io.schema import flatten_schema, schema_to_langflow_inputs
21
- from langflow.logging import logger
22
- from langflow.schema.data import Data
23
- from langflow.schema.dataframe import DataFrame
24
- from langflow.schema.message import Message
25
-
26
-
27
- def _patch_graph_clean_null_input_types() -> None:
28
- """Monkey-patch Graph._create_vertex to clean legacy templates."""
29
- try:
30
- from langflow.graph.graph.base import Graph
31
-
32
- original_create_vertex = Graph._create_vertex
33
-
34
- def _create_vertex_with_cleanup(self, frontend_data):
35
- try:
36
- node_id: str | None = frontend_data.get("id") if isinstance(frontend_data, dict) else None
37
- if node_id and "Composio" in node_id:
38
- template = frontend_data.get("data", {}).get("node", {}).get("template", {})
39
- if isinstance(template, dict):
40
- for field_cfg in template.values():
41
- if isinstance(field_cfg, dict) and field_cfg.get("input_types") is None:
42
- field_cfg["input_types"] = []
43
- except (AttributeError, TypeError, KeyError) as e:
44
- logger.debug(f"Composio template cleanup encountered error: {e}")
45
-
46
- return original_create_vertex(self, frontend_data)
47
-
48
- # Patch only once
49
- if getattr(Graph, "_composio_patch_applied", False) is False:
50
- Graph._create_vertex = _create_vertex_with_cleanup # type: ignore[method-assign]
51
- Graph._composio_patch_applied = True # type: ignore[attr-defined]
52
- logger.debug("Applied Composio template cleanup patch to Graph._create_vertex")
53
-
54
- except (AttributeError, TypeError) as e:
55
- logger.debug(f"Failed to apply Composio Graph patch: {e}")
56
-
57
-
58
- # Apply the patch at import time
59
- _patch_graph_clean_null_input_types()
60
-
61
-
62
- class ComposioBaseComponent(Component):
63
- """Base class for Composio components with common functionality."""
64
-
65
- default_tools_limit: int = 5
66
-
67
- _base_inputs = [
68
- MessageTextInput(
69
- name="entity_id",
70
- display_name="Entity ID",
71
- value="default",
72
- advanced=True,
73
- tool_mode=True,
74
- ),
75
- SecretStrInput(
76
- name="api_key",
77
- display_name="Composio API Key",
78
- required=True,
79
- real_time_refresh=True,
80
- value="COMPOSIO_API_KEY",
81
- ),
82
- AuthInput(
83
- name="auth_link",
84
- value="",
85
- auth_tooltip="Please insert a valid Composio API Key.",
86
- show=False,
87
- ),
88
- SortableListInput(
89
- name="action_button",
90
- display_name="Action",
91
- placeholder="Select action",
92
- options=[],
93
- value="disabled",
94
- helper_text="Please connect before selecting actions.",
95
- helper_text_metadata={"variant": "destructive"},
96
- show=True,
97
- required=False,
98
- real_time_refresh=True,
99
- limit=1,
100
- ),
101
- ]
102
-
103
- _name_sanitizer = re.compile(r"[^a-zA-Z0-9_-]")
104
-
105
- # Class-level caches
106
- _actions_cache: dict[str, dict[str, Any]] = {}
107
- _action_schema_cache: dict[str, dict[str, Any]] = {}
108
-
109
- outputs = [
110
- Output(name="dataFrame", display_name="DataFrame", method="as_dataframe"),
111
- ]
112
-
113
- inputs = list(_base_inputs)
114
-
115
- def __init__(self, **kwargs):
116
- """Initialize instance variables to prevent shared state between components."""
117
- super().__init__(**kwargs)
118
- self._all_fields: set[str] = set()
119
- self._bool_variables: set[str] = set()
120
- self._actions_data: dict[str, dict[str, Any]] = {}
121
- self._default_tools: set[str] = set()
122
- self._display_to_key_map: dict[str, str] = {}
123
- self._key_to_display_map: dict[str, str] = {}
124
- self._sanitized_names: dict[str, str] = {}
125
- self._action_schemas: dict[str, Any] = {}
126
-
127
- def as_message(self) -> Message:
128
- result = self.execute_action()
129
- if result is None:
130
- return Message(text="Action execution returned no result")
131
- return Message(text=str(result))
132
-
133
- def as_dataframe(self) -> DataFrame:
134
- result = self.execute_action()
135
-
136
- if isinstance(result, dict):
137
- result = [result]
138
- # Build DataFrame and avoid exposing a 'data' attribute via column access,
139
- result_dataframe = DataFrame(result)
140
- if hasattr(result_dataframe, "columns"):
141
- try:
142
- if "data" in result_dataframe.columns:
143
- result_dataframe = result_dataframe.rename(columns={"data": "_data"})
144
- except (AttributeError, TypeError, ValueError, KeyError) as e:
145
- logger.debug(f"Failed to rename 'data' column: {e}")
146
- return result_dataframe
147
-
148
- def as_data(self) -> Data:
149
- result = self.execute_action()
150
- return Data(results=result)
151
-
152
- def _build_action_maps(self):
153
- """Build lookup maps for action names."""
154
- if not self._display_to_key_map or not self._key_to_display_map:
155
- self._display_to_key_map = {data["display_name"]: key for key, data in self._actions_data.items()}
156
- self._key_to_display_map = {key: data["display_name"] for key, data in self._actions_data.items()}
157
- self._sanitized_names = {
158
- action: self._name_sanitizer.sub("-", self.sanitize_action_name(action))
159
- for action in self._actions_data
160
- }
161
-
162
- def sanitize_action_name(self, action_name: str) -> str:
163
- """Convert action name to display name using lookup."""
164
- self._build_action_maps()
165
- return self._key_to_display_map.get(action_name, action_name)
166
-
167
- def desanitize_action_name(self, action_name: str) -> str:
168
- """Convert display name to action key using lookup."""
169
- self._build_action_maps()
170
- return self._display_to_key_map.get(action_name, action_name)
171
-
172
- def _get_action_fields(self, action_key: str | None) -> set[str]:
173
- """Get fields for an action."""
174
- if action_key is None:
175
- return set()
176
- return set(self._actions_data[action_key]["action_fields"]) if action_key in self._actions_data else set()
177
-
178
- def _build_wrapper(self) -> Composio:
179
- """Build the Composio wrapper."""
180
- try:
181
- if not self.api_key:
182
- msg = "Composio API Key is required"
183
- raise ValueError(msg)
184
- return Composio(api_key=self.api_key, provider=LangchainProvider())
185
-
186
- except ValueError as e:
187
- logger.error(f"Error building Composio wrapper: {e}")
188
- msg = "Please provide a valid Composio API Key in the component settings"
189
- raise ValueError(msg) from e
190
-
191
- def show_hide_fields(self, build_config: dict, field_value: Any):
192
- """Optimized field visibility updates by only modifying show values."""
193
- if not field_value:
194
- for field in self._all_fields:
195
- build_config[field]["show"] = False
196
- if field in self._bool_variables:
197
- build_config[field]["value"] = False
198
- else:
199
- build_config[field]["value"] = ""
200
- return
201
-
202
- action_key = None
203
- if isinstance(field_value, list) and field_value:
204
- action_key = self.desanitize_action_name(field_value[0]["name"])
205
- else:
206
- action_key = field_value
207
-
208
- fields_to_show = self._get_action_fields(action_key)
209
-
210
- for field in self._all_fields:
211
- should_show = field in fields_to_show
212
- if build_config[field]["show"] != should_show:
213
- build_config[field]["show"] = should_show
214
- if not should_show:
215
- if field in self._bool_variables:
216
- build_config[field]["value"] = False
217
- else:
218
- build_config[field]["value"] = ""
219
-
220
- def _populate_actions_data(self):
221
- """Fetch the list of actions for the toolkit and build helper maps."""
222
- if self._actions_data:
223
- return
224
-
225
- # Try to load from the class-level cache
226
- toolkit_slug = self.app_name.lower()
227
- if toolkit_slug in self.__class__._actions_cache:
228
- # Deep-copy so that any mutation on this instance does not affect the
229
- # cached master copy.
230
- self._actions_data = copy.deepcopy(self.__class__._actions_cache[toolkit_slug])
231
- self._action_schemas = copy.deepcopy(self.__class__._action_schema_cache.get(toolkit_slug, {}))
232
- logger.debug(f"Loaded actions for {toolkit_slug} from in-process cache")
233
- return
234
-
235
- api_key = getattr(self, "api_key", None)
236
- if not api_key:
237
- logger.warning("API key is missing. Cannot populate actions data.")
238
- return
239
-
240
- try:
241
- composio = self._build_wrapper()
242
- toolkit_slug = self.app_name.lower()
243
-
244
- raw_tools = composio.tools.get_raw_composio_tools(toolkits=[toolkit_slug], limit=999)
245
-
246
- if not raw_tools:
247
- msg = f"Toolkit '{toolkit_slug}' not found or has no available tools"
248
- raise ValueError(msg)
249
-
250
- for raw_tool in raw_tools:
251
- try:
252
- # Convert raw_tool to dict-like structure
253
- tool_dict = raw_tool.__dict__ if hasattr(raw_tool, "__dict__") else raw_tool
254
-
255
- if not tool_dict:
256
- logger.warning(f"Tool is None or empty: {raw_tool}")
257
- continue
258
-
259
- action_key = tool_dict.get("slug")
260
- if not action_key:
261
- logger.warning(f"Action key (slug) is missing in tool: {tool_dict}")
262
- continue
263
-
264
- # Human-friendly display name
265
- display_name = tool_dict.get("name") or tool_dict.get("display_name")
266
- if not display_name:
267
- # Better fallback: convert GMAIL_SEND_EMAIL to "Send Email"
268
- # Remove app prefix and convert to title case
269
- clean_name = action_key
270
- clean_name = clean_name.removeprefix(f"{self.app_name.upper()}_")
271
- # Convert underscores to spaces and title case
272
- display_name = clean_name.replace("_", " ").title()
273
-
274
- # Build list of parameter names and track bool fields
275
- parameters_schema = tool_dict.get("input_parameters", {})
276
- if parameters_schema is None:
277
- logger.warning(f"Parameters schema is None for action key: {action_key}")
278
- # Still add the action but with empty fields
279
- self._action_schemas[action_key] = tool_dict
280
- self._actions_data[action_key] = {
281
- "display_name": display_name,
282
- "action_fields": [],
283
- "file_upload_fields": set(),
284
- }
285
- continue
286
-
287
- try:
288
- # Special handling for unusual schema structures
289
- if not isinstance(parameters_schema, dict):
290
- # Try to convert if it's a model object
291
- if hasattr(parameters_schema, "model_dump"):
292
- parameters_schema = parameters_schema.model_dump()
293
- elif hasattr(parameters_schema, "__dict__"):
294
- parameters_schema = parameters_schema.__dict__
295
- else:
296
- logger.warning(f"Cannot process parameters schema for {action_key}, skipping")
297
- self._action_schemas[action_key] = tool_dict
298
- self._actions_data[action_key] = {
299
- "display_name": display_name,
300
- "action_fields": [],
301
- "file_upload_fields": set(),
302
- }
303
- continue
304
-
305
- # Validate parameters_schema has required structure before flattening
306
- if not parameters_schema.get("properties") and not parameters_schema.get("$defs"):
307
- # Create a minimal valid schema to avoid errors
308
- parameters_schema = {"type": "object", "properties": {}}
309
-
310
- # Sanitize the schema before passing to flatten_schema
311
- # Handle case where 'required' is explicitly None (causes "'NoneType' object is not iterable")
312
- if parameters_schema.get("required") is None:
313
- parameters_schema = parameters_schema.copy() # Don't modify the original
314
- parameters_schema["required"] = []
315
-
316
- try:
317
- # Preserve original descriptions before flattening to restore if lost
318
- original_descriptions = {}
319
- original_props = parameters_schema.get("properties", {})
320
- for prop_name, prop_schema in original_props.items():
321
- if isinstance(prop_schema, dict) and "description" in prop_schema:
322
- original_descriptions[prop_name] = prop_schema["description"]
323
-
324
- flat_schema = flatten_schema(parameters_schema)
325
-
326
- # Restore lost descriptions in flattened schema
327
- if flat_schema and isinstance(flat_schema, dict) and "properties" in flat_schema:
328
- flat_props = flat_schema["properties"]
329
- for field_name, field_schema in flat_props.items():
330
- # Check if this field lost its description during flattening
331
- if isinstance(field_schema, dict) and "description" not in field_schema:
332
- # Try to find the original description
333
- # Handle array fields like bcc[0] -> bcc
334
- base_field_name = field_name.replace("[0]", "")
335
- if base_field_name in original_descriptions:
336
- field_schema["description"] = original_descriptions[base_field_name]
337
- elif field_name in original_descriptions:
338
- field_schema["description"] = original_descriptions[field_name]
339
- except (KeyError, TypeError, ValueError):
340
- self._action_schemas[action_key] = tool_dict
341
- self._actions_data[action_key] = {
342
- "display_name": display_name,
343
- "action_fields": [],
344
- "file_upload_fields": set(),
345
- }
346
- continue
347
-
348
- if flat_schema is None:
349
- logger.warning(f"Flat schema is None for action key: {action_key}")
350
- # Still add the action but with empty fields so the UI doesn't break
351
- self._action_schemas[action_key] = tool_dict
352
- self._actions_data[action_key] = {
353
- "display_name": display_name,
354
- "action_fields": [],
355
- "file_upload_fields": set(),
356
- }
357
- continue
358
-
359
- # Extract field names and detect file upload fields during parsing
360
- raw_action_fields = list(flat_schema.get("properties", {}).keys())
361
- action_fields = []
362
- attachment_related_found = False
363
- file_upload_fields = set()
364
-
365
- # Check original schema properties for file_uploadable fields
366
- original_props = parameters_schema.get("properties", {})
367
- for field_name, field_schema in original_props.items():
368
- if isinstance(field_schema, dict):
369
- clean_field_name = field_name.replace("[0]", "")
370
- # Check direct file_uploadable attribute
371
- if field_schema.get("file_uploadable") is True:
372
- file_upload_fields.add(clean_field_name)
373
-
374
- # Check anyOf structures (like OUTLOOK_OUTLOOK_SEND_EMAIL)
375
- if "anyOf" in field_schema:
376
- for any_of_item in field_schema["anyOf"]:
377
- if isinstance(any_of_item, dict) and any_of_item.get("file_uploadable") is True:
378
- file_upload_fields.add(clean_field_name)
379
-
380
- for field in raw_action_fields:
381
- clean_field = field.replace("[0]", "")
382
- # Check if this field is attachment-related
383
- if clean_field.lower().startswith("attachment."):
384
- attachment_related_found = True
385
- continue # Skip individual attachment fields
386
-
387
- # Handle conflicting field names - rename user_id to avoid conflicts with entity_id
388
- if clean_field == "user_id":
389
- clean_field = f"{self.app_name}_user_id"
390
- elif clean_field == "status":
391
- clean_field = f"{self.app_name}_status"
392
-
393
- action_fields.append(clean_field)
394
-
395
- # Add consolidated attachment field if we found attachment-related fields
396
- if attachment_related_found:
397
- action_fields.append("attachment")
398
- file_upload_fields.add("attachment") # Attachment fields are also file upload fields
399
-
400
- # Track boolean parameters so we can coerce them later
401
- properties = flat_schema.get("properties", {})
402
- if properties:
403
- for p_name, p_schema in properties.items():
404
- if isinstance(p_schema, dict) and p_schema.get("type") == "boolean":
405
- # Use cleaned field name for boolean tracking
406
- clean_field_name = p_name.replace("[0]", "")
407
- self._bool_variables.add(clean_field_name)
408
-
409
- self._action_schemas[action_key] = tool_dict
410
- self._actions_data[action_key] = {
411
- "display_name": display_name,
412
- "action_fields": action_fields,
413
- "file_upload_fields": file_upload_fields,
414
- }
415
-
416
- except (KeyError, TypeError, ValueError) as flatten_error:
417
- logger.error(f"flatten_schema failed for {action_key}: {flatten_error}")
418
- self._action_schemas[action_key] = tool_dict
419
- self._actions_data[action_key] = {
420
- "display_name": display_name,
421
- "action_fields": [],
422
- "file_upload_fields": set(),
423
- }
424
- continue
425
-
426
- except ValueError as e:
427
- logger.warning(f"Failed processing Composio tool for action {raw_tool}: {e}")
428
-
429
- # Helper look-ups used elsewhere
430
- self._all_fields = {f for d in self._actions_data.values() for f in d["action_fields"]}
431
- self._build_action_maps()
432
-
433
- # Cache actions for this toolkit so subsequent component instances
434
- # can reuse them without hitting the Composio API again.
435
- self.__class__._actions_cache[toolkit_slug] = copy.deepcopy(self._actions_data)
436
- self.__class__._action_schema_cache[toolkit_slug] = copy.deepcopy(self._action_schemas)
437
-
438
- except ValueError as e:
439
- logger.debug(f"Could not populate Composio actions for {self.app_name}: {e}")
440
-
441
- def _validate_schema_inputs(self, action_key: str) -> list[InputTypes]:
442
- """Convert the JSON schema for *action_key* into Langflow input objects."""
443
- # Skip validation for default/placeholder values
444
- if action_key in ("disabled", "placeholder", ""):
445
- logger.debug(f"Skipping schema validation for placeholder value: {action_key}")
446
- return []
447
-
448
- schema_dict = self._action_schemas.get(action_key)
449
- if not schema_dict:
450
- logger.warning(f"No schema found for action key: {action_key}")
451
- return []
452
-
453
- try:
454
- parameters_schema = schema_dict.get("input_parameters", {})
455
- if parameters_schema is None:
456
- logger.warning(f"Parameters schema is None for action key: {action_key}")
457
- return []
458
-
459
- # Check if parameters_schema has the expected structure
460
- if not isinstance(parameters_schema, dict):
461
- logger.warning(
462
- f"Parameters schema is not a dict for action key: {action_key}, got: {type(parameters_schema)}"
463
- )
464
- return []
465
-
466
- # Validate parameters_schema has required structure before flattening
467
- if not parameters_schema.get("properties") and not parameters_schema.get("$defs"):
468
- # Create a minimal valid schema to avoid errors
469
- parameters_schema = {"type": "object", "properties": {}}
470
-
471
- # Sanitize the schema before passing to flatten_schema
472
- # Handle case where 'required' is explicitly None (causes "'NoneType' object is not iterable")
473
- if parameters_schema.get("required") is None:
474
- parameters_schema = parameters_schema.copy() # Don't modify the original
475
- parameters_schema["required"] = []
476
-
477
- try:
478
- # Preserve original descriptions before flattening to restore if lost
479
- original_descriptions = {}
480
- original_props = parameters_schema.get("properties", {})
481
- for prop_name, prop_schema in original_props.items():
482
- if isinstance(prop_schema, dict) and "description" in prop_schema:
483
- original_descriptions[prop_name] = prop_schema["description"]
484
-
485
- flat_schema = flatten_schema(parameters_schema)
486
-
487
- # Restore lost descriptions in flattened schema
488
- if flat_schema and isinstance(flat_schema, dict) and "properties" in flat_schema:
489
- flat_props = flat_schema["properties"]
490
- for field_name, field_schema in flat_props.items():
491
- # Check if this field lost its description during flattening
492
- if isinstance(field_schema, dict) and "description" not in field_schema:
493
- # Try to find the original description
494
- # Handle array fields like bcc[0] -> bcc
495
- base_field_name = field_name.replace("[0]", "")
496
- if base_field_name in original_descriptions:
497
- field_schema["description"] = original_descriptions[base_field_name]
498
- elif field_name in original_descriptions:
499
- field_schema["description"] = original_descriptions[field_name]
500
- except (KeyError, TypeError, ValueError) as flatten_error:
501
- logger.error(f"flatten_schema failed for {action_key}: {flatten_error}")
502
- return []
503
-
504
- if flat_schema is None:
505
- logger.warning(f"Flat schema is None for action key: {action_key}")
506
- return []
507
-
508
- # Additional check for flat_schema structure
509
- if not isinstance(flat_schema, dict):
510
- logger.warning(f"Flat schema is not a dict for action key: {action_key}, got: {type(flat_schema)}")
511
- return []
512
-
513
- # Ensure flat_schema has the expected structure for create_input_schema_from_json_schema
514
- if flat_schema.get("type") != "object":
515
- logger.warning(f"Flat schema for {action_key} is not of type 'object', got: {flat_schema.get('type')}")
516
- # Fix the schema type if it's missing
517
- flat_schema["type"] = "object"
518
-
519
- if "properties" not in flat_schema:
520
- flat_schema["properties"] = {}
521
-
522
- # Clean up field names - remove [0] suffixes from array fields
523
- cleaned_properties = {}
524
- attachment_related_fields = set() # Track fields that are attachment-related
525
-
526
- for field_name, field_schema in flat_schema.get("properties", {}).items():
527
- # Remove [0] suffix from field names (e.g., "bcc[0]" -> "bcc", "cc[0]" -> "cc")
528
- clean_field_name = field_name.replace("[0]", "")
529
-
530
- # Check if this field is attachment-related (contains "attachment." prefix)
531
- if clean_field_name.lower().startswith("attachment."):
532
- attachment_related_fields.add(clean_field_name)
533
- # Don't add individual attachment sub-fields to the schema
534
- continue
535
-
536
- # Handle conflicting field names - rename user_id to avoid conflicts with entity_id
537
- if clean_field_name == "user_id":
538
- clean_field_name = f"{self.app_name}_user_id"
539
- # Update
540
- field_schema_copy = field_schema.copy()
541
- field_schema_copy["description"] = (
542
- f"User ID for {self.app_name.title()}: " + field_schema["description"]
543
- )
544
- elif clean_field_name == "status":
545
- clean_field_name = f"{self.app_name}_status"
546
- # Update
547
- field_schema_copy = field_schema.copy()
548
- field_schema_copy["description"] = (
549
- f"Status for {self.app_name.title()}: " + field_schema["description"]
550
- )
551
- else:
552
- # Use the original field schema for all other fields
553
- field_schema_copy = field_schema
554
-
555
- # Preserve the full schema information, not just the type
556
- cleaned_properties[clean_field_name] = field_schema_copy
557
-
558
- # If we found attachment-related fields, add a single "attachment" field
559
- if attachment_related_fields:
560
- # Create a generic attachment field schema
561
- attachment_schema = {
562
- "type": "string",
563
- "description": "File attachment for the email",
564
- "title": "Attachment",
565
- }
566
- cleaned_properties["attachment"] = attachment_schema
567
-
568
- # Update the flat schema with cleaned field names
569
- flat_schema["properties"] = cleaned_properties
570
-
571
- # Also update required fields to match cleaned names
572
- if flat_schema.get("required"):
573
- cleaned_required = [field.replace("[0]", "") for field in flat_schema["required"]]
574
- flat_schema["required"] = cleaned_required
575
-
576
- input_schema = create_input_schema_from_json_schema(flat_schema)
577
- if input_schema is None:
578
- logger.warning(f"Input schema is None for action key: {action_key}")
579
- return []
580
-
581
- # Additional safety check before calling schema_to_langflow_inputs
582
- if not hasattr(input_schema, "model_fields"):
583
- logger.warning(f"Input schema for {action_key} does not have model_fields attribute")
584
- return []
585
-
586
- if input_schema.model_fields is None:
587
- logger.warning(f"Input schema model_fields is None for {action_key}")
588
- return []
589
-
590
- result = schema_to_langflow_inputs(input_schema)
591
-
592
- # Process inputs to handle attachment fields and set advanced status
593
- if result:
594
- processed_inputs = []
595
- required_fields_set = set(flat_schema.get("required", []))
596
-
597
- # Get file upload fields from stored action data
598
- file_upload_fields = self._actions_data.get(action_key, {}).get("file_upload_fields", set())
599
- if attachment_related_fields: # If we consolidated attachment fields
600
- file_upload_fields = file_upload_fields | {"attachment"}
601
-
602
- for inp in result:
603
- if hasattr(inp, "name") and inp.name is not None:
604
- # Check if this specific field is a file upload field
605
- if inp.name.lower() in file_upload_fields or inp.name.lower() == "attachment":
606
- # Replace with FileInput for file upload fields
607
- file_input = FileInput(
608
- name=inp.name,
609
- display_name=getattr(inp, "display_name", inp.name.replace("_", " ").title()),
610
- required=inp.name in required_fields_set,
611
- advanced=inp.name not in required_fields_set,
612
- info=getattr(inp, "info", "Upload file for this field"),
613
- show=True,
614
- file_types=[
615
- "csv",
616
- "txt",
617
- "doc",
618
- "docx",
619
- "xls",
620
- "xlsx",
621
- "pdf",
622
- "png",
623
- "jpg",
624
- "jpeg",
625
- "gif",
626
- "zip",
627
- "rar",
628
- "ppt",
629
- "pptx",
630
- ],
631
- )
632
- processed_inputs.append(file_input)
633
- else:
634
- # Ensure proper display_name and info are set for regular fields
635
- if not hasattr(inp, "display_name") or not inp.display_name:
636
- inp.display_name = inp.name.replace("_", " ").title()
637
-
638
- # Preserve description from schema if available
639
- field_schema = flat_schema.get("properties", {}).get(inp.name, {})
640
- schema_description = field_schema.get("description")
641
- current_info = getattr(inp, "info", None)
642
-
643
- # Use schema description if available, otherwise keep current info or create from name
644
- if schema_description:
645
- inp.info = schema_description
646
- elif not current_info:
647
- # Fallback: create a basic description from the field name if no description exists
648
- inp.info = f"{inp.name.replace('_', ' ').title()} field"
649
-
650
- # Set advanced status for non-file-upload fields
651
- if inp.name not in required_fields_set:
652
- inp.advanced = True
653
-
654
- # Skip entity_id being mapped to user_id parameter
655
- if inp.name == "user_id" and getattr(self, "entity_id", None) == getattr(
656
- inp, "value", None
657
- ):
658
- continue
659
-
660
- processed_inputs.append(inp)
661
- else:
662
- processed_inputs.append(inp)
663
-
664
- return processed_inputs
665
- return result # noqa: TRY300
666
- except ValueError as e:
667
- logger.warning(f"Error generating inputs for {action_key}: {e}")
668
- return []
669
-
670
- def _get_inputs_for_all_actions(self) -> dict[str, list[InputTypes]]:
671
- """Return a mapping action_key → list[InputTypes] for every action."""
672
- result: dict[str, list[InputTypes]] = {}
673
- for key in self._actions_data:
674
- result[key] = self._validate_schema_inputs(key)
675
- return result
676
-
677
- def _remove_inputs_from_build_config(self, build_config: dict, keep_for_action: str) -> None:
678
- """Remove parameter UI fields that belong to other actions."""
679
- protected_keys = {"code", "entity_id", "api_key", "auth_link", "action_button", "tool_mode"}
680
-
681
- for action_key, lf_inputs in self._get_inputs_for_all_actions().items():
682
- if action_key == keep_for_action:
683
- continue
684
- for inp in lf_inputs:
685
- if inp.name is not None and inp.name not in protected_keys:
686
- build_config.pop(inp.name, None)
687
-
688
- def _update_action_config(self, build_config: dict, selected_value: Any) -> None:
689
- """Add or update parameter input fields for the chosen action."""
690
- if not selected_value:
691
- return
692
-
693
- # The UI passes either a list with dict [{name: display_name}] OR the raw key
694
- if isinstance(selected_value, list) and selected_value:
695
- display_name = selected_value[0]["name"]
696
- else:
697
- display_name = selected_value
698
-
699
- action_key = self.desanitize_action_name(display_name)
700
-
701
- # Skip validation for default/placeholder values
702
- if action_key in ("disabled", "placeholder", ""):
703
- logger.debug(f"Skipping action config update for placeholder value: {action_key}")
704
- return
705
-
706
- lf_inputs = self._validate_schema_inputs(action_key)
707
-
708
- # First remove inputs belonging to other actions
709
- self._remove_inputs_from_build_config(build_config, action_key)
710
-
711
- # Add / update the inputs for this action
712
- for inp in lf_inputs:
713
- if inp.name is not None:
714
- inp_dict = inp.to_dict() if hasattr(inp, "to_dict") else inp.__dict__.copy()
715
-
716
- # Ensure input_types is always a list
717
- if not isinstance(inp_dict.get("input_types"), list):
718
- inp_dict["input_types"] = []
719
-
720
- inp_dict.setdefault("show", True) # visible once action selected
721
- # Preserve previously entered value if user already filled something
722
- if inp.name in build_config:
723
- existing_val = build_config[inp.name].get("value")
724
- inp_dict.setdefault("value", existing_val)
725
- build_config[inp.name] = inp_dict
726
-
727
- # Ensure _all_fields includes new ones
728
- self._all_fields.update({i.name for i in lf_inputs if i.name is not None})
729
-
730
- def _is_tool_mode_enabled(self) -> bool:
731
- """Check if tool_mode is currently enabled."""
732
- return getattr(self, "tool_mode", False)
733
-
734
- def _set_action_visibility(self, build_config: dict, *, force_show: bool | None = None) -> None:
735
- """Set action field visibility based on tool_mode state or forced value."""
736
- if force_show is not None:
737
- build_config["action_button"]["show"] = force_show
738
- else:
739
- # When tool_mode is enabled, hide action field
740
- build_config["action_button"]["show"] = not self._is_tool_mode_enabled()
741
-
742
- def create_new_auth_config(self, app_name: str) -> str:
743
- """Create a new auth config for the given app name."""
744
- composio = self._build_wrapper()
745
- auth_config = composio.auth_configs.create(toolkit=app_name, options={"type": "use_composio_managed_auth"})
746
- return auth_config.id
747
-
748
- def _initiate_connection(self, app_name: str) -> tuple[str, str]:
749
- """Initiate OAuth connection and return (redirect_url, connection_id)."""
750
- try:
751
- composio = self._build_wrapper()
752
-
753
- auth_configs = composio.auth_configs.list(toolkit_slug=app_name)
754
- if len(auth_configs.items) == 0:
755
- auth_config_id = self.create_new_auth_config(app_name)
756
- else:
757
- auth_config_id = None
758
- for auth_config in auth_configs.items:
759
- if auth_config.auth_scheme == "OAUTH2":
760
- auth_config_id = auth_config.id
761
-
762
- auth_config_id = auth_configs.items[0].id
763
-
764
- connection_request = composio.connected_accounts.initiate(
765
- user_id=self.entity_id, auth_config_id=auth_config_id
766
- )
767
-
768
- redirect_url = getattr(connection_request, "redirect_url", None)
769
- connection_id = getattr(connection_request, "id", None)
770
-
771
- if not redirect_url or not redirect_url.startswith(("http://", "https://")):
772
- msg = "Invalid redirect URL received from Composio"
773
- raise ValueError(msg)
774
-
775
- if not connection_id:
776
- msg = "No connection ID received from Composio"
777
- raise ValueError(msg)
778
-
779
- logger.info(f"OAuth connection initiated for {app_name}: {redirect_url} (ID: {connection_id})")
780
- return redirect_url, connection_id # noqa: TRY300
781
-
782
- except Exception as e:
783
- logger.error(f"Error initiating connection for {app_name}: {e}")
784
- msg = f"Failed to initiate OAuth connection: {e}"
785
- raise ValueError(msg) from e
786
-
787
- def _check_connection_status_by_id(self, connection_id: str) -> str | None:
788
- """Check status of a specific connection by ID. Returns status or None if not found."""
789
- try:
790
- composio = self._build_wrapper()
791
- connection = composio.connected_accounts.get(nanoid=connection_id)
792
- status = getattr(connection, "status", None)
793
- logger.info(f"Connection {connection_id} status: {status}")
794
- except (ValueError, ConnectionError) as e:
795
- logger.error(f"Error checking connection {connection_id}: {e}")
796
- return None
797
- else:
798
- return status
799
-
800
- def _find_active_connection_for_app(self, app_name: str) -> tuple[str, str] | None:
801
- """Find any ACTIVE connection for this app/user. Returns (connection_id, status) or None."""
802
- try:
803
- composio = self._build_wrapper()
804
- connection_list = composio.connected_accounts.list(
805
- user_ids=[self.entity_id], toolkit_slugs=[app_name.lower()]
806
- )
807
-
808
- if connection_list and hasattr(connection_list, "items") and connection_list.items:
809
- for connection in connection_list.items:
810
- connection_id = getattr(connection, "id", None)
811
- connection_status = getattr(connection, "status", None)
812
- if connection_status == "ACTIVE" and connection_id:
813
- logger.info(f"Found existing ACTIVE connection for {app_name}: {connection_id}")
814
- return connection_id, connection_status
815
-
816
- except (ValueError, ConnectionError) as e:
817
- logger.error(f"Error finding active connection for {app_name}: {e}")
818
- return None
819
- else:
820
- return None
821
-
822
- def _disconnect_specific_connection(self, connection_id: str) -> None:
823
- """Disconnect a specific Composio connection by ID."""
824
- try:
825
- composio = self._build_wrapper()
826
- composio.connected_accounts.delete(nanoid=connection_id)
827
- logger.info(f"✅ Disconnected specific connection: {connection_id}")
828
-
829
- except Exception as e:
830
- logger.error(f"Error disconnecting connection {connection_id}: {e}")
831
- msg = f"Failed to disconnect connection {connection_id}: {e}"
832
- raise ValueError(msg) from e
833
-
834
- def update_build_config(self, build_config: dict, field_value: Any, field_name: str | None = None) -> dict:
835
- """Update build config for auth and action selection."""
836
- # Clean any legacy None values that may still be present
837
- for _fconfig in build_config.values():
838
- if isinstance(_fconfig, dict) and _fconfig.get("input_types") is None:
839
- _fconfig["input_types"] = []
840
-
841
- # BULLETPROOF tool_mode checking - check all possible places where tool_mode could be stored
842
- instance_tool_mode = getattr(self, "tool_mode", False) if hasattr(self, "tool_mode") else False
843
-
844
- # Check build_config for tool_mode in multiple possible structures
845
- build_config_tool_mode = False
846
- if "tool_mode" in build_config:
847
- tool_mode_config = build_config["tool_mode"]
848
- if isinstance(tool_mode_config, dict):
849
- build_config_tool_mode = tool_mode_config.get("value", False)
850
- else:
851
- build_config_tool_mode = bool(tool_mode_config)
852
-
853
- # If this is a tool_mode change, update BOTH instance variable AND build_config
854
- if field_name == "tool_mode":
855
- self.tool_mode = field_value
856
- instance_tool_mode = field_value
857
- # CRITICAL: Store tool_mode state in build_config so it persists
858
- if "tool_mode" not in build_config:
859
- build_config["tool_mode"] = {}
860
- if isinstance(build_config["tool_mode"], dict):
861
- build_config["tool_mode"]["value"] = field_value
862
- build_config_tool_mode = field_value
863
-
864
- # Current tool_mode is True if ANY source indicates it's enabled
865
- current_tool_mode = instance_tool_mode or build_config_tool_mode or (field_name == "tool_mode" and field_value)
866
-
867
- # CRITICAL: Ensure dynamic action metadata is available whenever we have an API key
868
- # This must happen BEFORE any early returns to ensure tools are always loaded
869
- api_key_available = hasattr(self, "api_key") and self.api_key
870
-
871
- # Check if we need to populate actions - but also check cache availability
872
- actions_available = bool(self._actions_data)
873
- toolkit_slug = getattr(self, "app_name", "").lower()
874
- cached_actions_available = toolkit_slug in self.__class__._actions_cache
875
-
876
- should_populate = False
877
-
878
- if (field_name == "api_key" and field_value) or (
879
- api_key_available and not actions_available and not cached_actions_available
880
- ):
881
- should_populate = True
882
- elif api_key_available and not actions_available and cached_actions_available:
883
- self._populate_actions_data()
884
-
885
- if should_populate:
886
- logger.info(f"Populating actions data for {getattr(self, 'app_name', 'unknown')}...")
887
- self._populate_actions_data()
888
- logger.info(f"Actions populated: {len(self._actions_data)} actions found")
889
-
890
- # CRITICAL: Set action options if we have actions (either from fresh population or cache)
891
- if self._actions_data:
892
- self._build_action_maps()
893
- build_config["action_button"]["options"] = [
894
- {"name": self.sanitize_action_name(action), "metadata": action} for action in self._actions_data
895
- ]
896
- logger.info(f"Action options set in build_config: {len(build_config['action_button']['options'])} options")
897
- else:
898
- build_config["action_button"]["options"] = []
899
- logger.warning("No actions found, setting empty options")
900
-
901
- # clear stored connection_id when api_key is changed
902
- if field_name == "api_key" and field_value:
903
- stored_connection_before = build_config.get("auth_link", {}).get("connection_id")
904
- if "auth_link" in build_config and "connection_id" in build_config["auth_link"]:
905
- build_config["auth_link"].pop("connection_id", None)
906
- build_config["auth_link"]["value"] = "connect"
907
- build_config["auth_link"]["auth_tooltip"] = "Connect"
908
- logger.info(f"Cleared stored connection_id '{stored_connection_before}' due to API key change")
909
- else:
910
- logger.info("DEBUG: EARLY No stored connection_id to clear on API key change")
911
-
912
- # Handle disconnect operations when tool mode is enabled
913
- if field_name == "auth_link" and field_value == "disconnect":
914
- try:
915
- # Get the specific connection ID that's currently being used
916
- stored_connection_id = build_config.get("auth_link", {}).get("connection_id")
917
- if stored_connection_id:
918
- self._disconnect_specific_connection(stored_connection_id)
919
- else:
920
- # No connection ID stored - nothing to disconnect
921
- logger.warning("No connection ID found to disconnect")
922
- build_config["auth_link"]["value"] = "connect"
923
- build_config["auth_link"]["auth_tooltip"] = "Connect"
924
- return build_config
925
- except (ValueError, ConnectionError) as e:
926
- logger.error(f"Error disconnecting: {e}")
927
- build_config["auth_link"]["value"] = "error"
928
- build_config["auth_link"]["auth_tooltip"] = f"Disconnect failed: {e!s}"
929
- return build_config
930
- else:
931
- build_config["auth_link"]["value"] = "connect"
932
- build_config["auth_link"]["auth_tooltip"] = "Connect"
933
- build_config["auth_link"].pop("connection_id", None) # Clear stored connection ID
934
- build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
935
- build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
936
- return build_config
937
-
938
- # Handle connection initiation when tool mode is enabled
939
- if field_name == "auth_link" and isinstance(field_value, dict):
940
- try:
941
- toolkit_slug = self.app_name.lower()
942
-
943
- # First check if we already have an ACTIVE connection
944
- existing_active = self._find_active_connection_for_app(self.app_name)
945
- if existing_active:
946
- connection_id, _ = existing_active
947
- build_config["auth_link"]["value"] = "validated"
948
- build_config["auth_link"]["auth_tooltip"] = "Disconnect"
949
- build_config["auth_link"]["connection_id"] = connection_id
950
- build_config["action_button"]["helper_text"] = ""
951
- build_config["action_button"]["helper_text_metadata"] = {}
952
- logger.info(f"Using existing ACTIVE connection {connection_id} for {toolkit_slug}")
953
- return build_config
954
-
955
- # Check if we have a stored connection ID with INITIATED status
956
- stored_connection_id = build_config.get("auth_link", {}).get("connection_id")
957
- if stored_connection_id:
958
- # Check status of existing connection
959
- status = self._check_connection_status_by_id(stored_connection_id)
960
- if status == "INITIATED":
961
- # Get redirect URL from stored connection
962
- try:
963
- composio = self._build_wrapper()
964
- connection = composio.connected_accounts.get(nanoid=stored_connection_id)
965
- state = getattr(connection, "state", None)
966
- if state and hasattr(state, "val"):
967
- redirect_url = getattr(state.val, "redirect_url", None)
968
- if redirect_url:
969
- build_config["auth_link"]["value"] = redirect_url
970
- logger.info(f"Reusing existing OAuth URL for {toolkit_slug}: {redirect_url}")
971
- return build_config
972
- except (AttributeError, ValueError, ConnectionError) as e:
973
- logger.debug(f"Could not retrieve connection {stored_connection_id}: {e}")
974
- # Continue to create new connection below
975
-
976
- # Create new OAuth connection ONLY if we truly have no usable connection yet
977
- if existing_active is None and not (stored_connection_id and status in ("ACTIVE", "INITIATED")):
978
- try:
979
- redirect_url, connection_id = self._initiate_connection(toolkit_slug)
980
- build_config["auth_link"]["value"] = redirect_url
981
- build_config["auth_link"]["connection_id"] = connection_id # Store connection ID
982
- logger.info(f"New OAuth URL created for {toolkit_slug}: {redirect_url}")
983
- except (ValueError, ConnectionError) as e:
984
- logger.error(f"Error creating OAuth connection: {e}")
985
- build_config["auth_link"]["value"] = "connect"
986
- build_config["auth_link"]["auth_tooltip"] = f"Error: {e!s}"
987
- else:
988
- return build_config
989
- else:
990
- # We already have a usable connection; no new OAuth request
991
- build_config["auth_link"]["auth_tooltip"] = "Disconnect"
992
-
993
- except (ValueError, ConnectionError) as e:
994
- logger.error(f"Error in connection initiation: {e}")
995
- build_config["auth_link"]["value"] = "connect"
996
- build_config["auth_link"]["auth_tooltip"] = f"Error: {e!s}"
997
- build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
998
- build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
999
- return build_config
1000
-
1001
- # Check for ACTIVE connections and update status accordingly (tool mode)
1002
- if hasattr(self, "api_key") and self.api_key:
1003
- stored_connection_id = build_config.get("auth_link", {}).get("connection_id")
1004
- active_connection_id = None
1005
-
1006
- # First try to check stored connection ID
1007
- if stored_connection_id:
1008
- status = self._check_connection_status_by_id(stored_connection_id)
1009
- if status == "ACTIVE":
1010
- active_connection_id = stored_connection_id
1011
-
1012
- # If no stored connection or stored connection is not ACTIVE, find any ACTIVE connection
1013
- if not active_connection_id:
1014
- active_connection = self._find_active_connection_for_app(self.app_name)
1015
- if active_connection:
1016
- active_connection_id, _ = active_connection
1017
- # Store the found active connection ID for future use
1018
- if "auth_link" not in build_config:
1019
- build_config["auth_link"] = {}
1020
- build_config["auth_link"]["connection_id"] = active_connection_id
1021
-
1022
- if active_connection_id:
1023
- # Show validated connection status
1024
- build_config["auth_link"]["value"] = "validated"
1025
- build_config["auth_link"]["auth_tooltip"] = "Disconnect"
1026
- build_config["action_button"]["helper_text"] = ""
1027
- build_config["action_button"]["helper_text_metadata"] = {}
1028
- else:
1029
- build_config["auth_link"]["value"] = "connect"
1030
- build_config["auth_link"]["auth_tooltip"] = "Connect"
1031
- build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
1032
- build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
1033
-
1034
- # CRITICAL: If tool_mode is enabled from ANY source, immediately hide action field and return
1035
- if current_tool_mode:
1036
- build_config["action_button"]["show"] = False
1037
-
1038
- # CRITICAL: Hide ALL action parameter fields when tool mode is enabled
1039
- for field in self._all_fields:
1040
- if field in build_config:
1041
- build_config[field]["show"] = False
1042
-
1043
- # Also hide any other action-related fields that might be in build_config
1044
- for field_name_in_config in build_config: # noqa: PLC0206
1045
- # Skip base fields like api_key, tool_mode, action, etc.
1046
- if (
1047
- field_name_in_config not in ["api_key", "tool_mode", "action_button", "auth_link", "entity_id"]
1048
- and isinstance(build_config[field_name_in_config], dict)
1049
- and "show" in build_config[field_name_in_config]
1050
- ):
1051
- build_config[field_name_in_config]["show"] = False
1052
-
1053
- # ENSURE tool_mode state is preserved in build_config for future calls
1054
- if "tool_mode" not in build_config:
1055
- build_config["tool_mode"] = {"value": True}
1056
- elif isinstance(build_config["tool_mode"], dict):
1057
- build_config["tool_mode"]["value"] = True
1058
- # Don't proceed with any other logic that might override this
1059
- return build_config
1060
-
1061
- if field_name == "tool_mode":
1062
- if field_value is True:
1063
- build_config["action_button"]["show"] = False # Hide action field when tool mode is enabled
1064
- for field in self._all_fields:
1065
- build_config[field]["show"] = False # Update show status for all fields based on tool mode
1066
- elif field_value is False:
1067
- build_config["action_button"]["show"] = True # Show action field when tool mode is disabled
1068
- for field in self._all_fields:
1069
- build_config[field]["show"] = True # Update show status for all fields based on tool mode
1070
- return build_config
1071
-
1072
- if field_name == "action_button":
1073
- self._update_action_config(build_config, field_value)
1074
- # Keep the existing show/hide behaviour
1075
- self.show_hide_fields(build_config, field_value)
1076
- return build_config
1077
-
1078
- # Handle API key removal
1079
- if field_name == "api_key" and len(field_value) == 0:
1080
- build_config["auth_link"]["value"] = ""
1081
- build_config["auth_link"]["auth_tooltip"] = "Please provide a valid Composio API Key."
1082
- build_config["action_button"]["options"] = []
1083
- build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
1084
- build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
1085
- build_config["auth_link"].pop("connection_id", None)
1086
- return build_config
1087
-
1088
- # Only proceed with connection logic if we have an API key
1089
- if not hasattr(self, "api_key") or not self.api_key:
1090
- return build_config
1091
-
1092
- # CRITICAL: If tool_mode is enabled (check both instance and build_config), skip all connection logic
1093
- if current_tool_mode:
1094
- build_config["action_button"]["show"] = False
1095
- return build_config
1096
-
1097
- # Update action options only if tool_mode is disabled
1098
- self._build_action_maps()
1099
- # Only set options if they haven't been set already during action population
1100
- if "options" not in build_config.get("action_button", {}) or not build_config["action_button"]["options"]:
1101
- build_config["action_button"]["options"] = [
1102
- {"name": self.sanitize_action_name(action), "metadata": action} for action in self._actions_data
1103
- ]
1104
- logger.debug("Setting action options from main logic path")
1105
- else:
1106
- logger.debug("Action options already set, skipping duplicate setting")
1107
- # Only set show=True if tool_mode is not enabled
1108
- if not current_tool_mode:
1109
- build_config["action_button"]["show"] = True
1110
-
1111
- stored_connection_id = build_config.get("auth_link", {}).get("connection_id")
1112
- active_connection_id = None
1113
-
1114
- if stored_connection_id:
1115
- status = self._check_connection_status_by_id(stored_connection_id)
1116
- if status == "ACTIVE":
1117
- active_connection_id = stored_connection_id
1118
-
1119
- if not active_connection_id:
1120
- active_connection = self._find_active_connection_for_app(self.app_name)
1121
- if active_connection:
1122
- active_connection_id, _ = active_connection
1123
- if "auth_link" not in build_config:
1124
- build_config["auth_link"] = {}
1125
- build_config["auth_link"]["connection_id"] = active_connection_id
1126
-
1127
- if active_connection_id:
1128
- build_config["auth_link"]["value"] = "validated"
1129
- build_config["auth_link"]["auth_tooltip"] = "Disconnect"
1130
- build_config["action_button"]["helper_text"] = ""
1131
- build_config["action_button"]["helper_text_metadata"] = {}
1132
- elif stored_connection_id:
1133
- status = self._check_connection_status_by_id(stored_connection_id)
1134
- if status == "INITIATED":
1135
- current_value = build_config.get("auth_link", {}).get("value")
1136
- if not current_value or current_value == "connect":
1137
- build_config["auth_link"]["value"] = "connect"
1138
- build_config["auth_link"]["auth_tooltip"] = "Connect"
1139
- build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
1140
- build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
1141
- else:
1142
- # Connection not found or other status
1143
- build_config["auth_link"]["value"] = "connect"
1144
- build_config["auth_link"]["auth_tooltip"] = "Connect"
1145
- build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
1146
- build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
1147
- else:
1148
- build_config["auth_link"]["value"] = "connect"
1149
- build_config["auth_link"]["auth_tooltip"] = "Connect"
1150
- build_config["action_button"]["helper_text"] = "Please connect before selecting actions."
1151
- build_config["action_button"]["helper_text_metadata"] = {"variant": "destructive"}
1152
-
1153
- if self._is_tool_mode_enabled():
1154
- build_config["action_button"]["show"] = False
1155
-
1156
- return build_config
1157
-
1158
- def configure_tools(self, composio: Composio, limit: int | None = None) -> list[Tool]:
1159
- if limit is None:
1160
- limit = 999
1161
-
1162
- tools = composio.tools.get(user_id=self.entity_id, toolkits=[self.app_name.lower()], limit=limit)
1163
- configured_tools = []
1164
- for tool in tools:
1165
- # Set the sanitized name
1166
- display_name = self._actions_data.get(tool.name, {}).get(
1167
- "display_name", self._sanitized_names.get(tool.name, self._name_sanitizer.sub("-", tool.name))
1168
- )
1169
- # Set the tags
1170
- tool.tags = [tool.name]
1171
- tool.metadata = {"display_name": display_name, "display_description": tool.description, "readonly": True}
1172
- configured_tools.append(tool)
1173
- return configured_tools
1174
-
1175
- async def _get_tools(self) -> list[Tool]:
1176
- """Get tools with cached results and optimized name sanitization."""
1177
- composio = self._build_wrapper()
1178
- self.set_default_tools()
1179
- return self.configure_tools(composio)
1180
-
1181
- @property
1182
- def enabled_tools(self):
1183
- """Return tag names for actions of this app that should be exposed to the agent.
1184
-
1185
- If default tools are set via set_default_tools(), returns those.
1186
- Otherwise, returns only the first few tools (limited by default_tools_limit)
1187
- to prevent overwhelming the agent. Subclasses can override this behavior.
1188
-
1189
- """
1190
- if not self._actions_data:
1191
- self._populate_actions_data()
1192
-
1193
- if hasattr(self, "_default_tools") and self._default_tools:
1194
- return list(self._default_tools)
1195
-
1196
- all_tools = list(self._actions_data.keys())
1197
- limit = getattr(self, "default_tools_limit", 5)
1198
- return all_tools[:limit]
1199
-
1200
- def execute_action(self):
1201
- """Execute the selected Composio tool."""
1202
- composio = self._build_wrapper()
1203
- self._populate_actions_data()
1204
- self._build_action_maps()
1205
-
1206
- display_name = (
1207
- self.action_button[0]["name"]
1208
- if isinstance(getattr(self, "action_button", None), list) and self.action_button
1209
- else self.action_button
1210
- )
1211
- action_key = self._display_to_key_map.get(display_name)
1212
-
1213
- if not action_key:
1214
- msg = f"Invalid action: {display_name}"
1215
- raise ValueError(msg)
1216
-
1217
- try:
1218
- arguments: dict[str, Any] = {}
1219
- param_fields = self._actions_data.get(action_key, {}).get("action_fields", [])
1220
-
1221
- schema_dict = self._action_schemas.get(action_key, {})
1222
- parameters_schema = schema_dict.get("input_parameters", {})
1223
- schema_properties = parameters_schema.get("properties", {}) if parameters_schema else {}
1224
- # Handle case where 'required' field is None (causes "'NoneType' object is not iterable")
1225
- required_list = parameters_schema.get("required", []) if parameters_schema else []
1226
- required_fields = set(required_list) if required_list is not None else set()
1227
-
1228
- for field in param_fields:
1229
- if not hasattr(self, field):
1230
- continue
1231
- value = getattr(self, field)
1232
-
1233
- # Skip None, empty strings, and empty lists
1234
- if value is None or value == "" or (isinstance(value, list) and len(value) == 0):
1235
- continue
1236
-
1237
- # For optional fields, be more strict about including them
1238
- # Only include if the user has explicitly provided a meaningful value
1239
- if field not in required_fields:
1240
- # Get the default value from the schema
1241
- field_schema = schema_properties.get(field, {})
1242
- schema_default = field_schema.get("default")
1243
-
1244
- # Skip if the current value matches the schema default
1245
- if value == schema_default:
1246
- continue
1247
-
1248
- # Convert comma-separated to list for array parameters (heuristic)
1249
- prop_schema = schema_properties.get(field, {})
1250
- if prop_schema.get("type") == "array" and isinstance(value, str):
1251
- value = [item.strip() for item in value.split(",")]
1252
-
1253
- if field in self._bool_variables:
1254
- value = bool(value)
1255
-
1256
- # Handle renamed fields - map back to original names for API execution
1257
- final_field_name = field
1258
- if field.endswith("_user_id") and field.startswith(self.app_name):
1259
- final_field_name = "user_id"
1260
- elif field.endswith("_status") and field.startswith(self.app_name):
1261
- final_field_name = "status"
1262
-
1263
- arguments[final_field_name] = value
1264
-
1265
- # Execute using new SDK
1266
- result = composio.tools.execute(
1267
- slug=action_key,
1268
- arguments=arguments,
1269
- user_id=self.entity_id,
1270
- )
1271
-
1272
- if isinstance(result, dict) and "successful" in result:
1273
- if result["successful"]:
1274
- raw_data = result.get("data", result)
1275
- return self._apply_post_processor(action_key, raw_data)
1276
- error_msg = result.get("error", "Tool execution failed")
1277
- raise ValueError(error_msg)
1278
-
1279
- except ValueError as e:
1280
- logger.error(f"Failed to execute {action_key}: {e}")
1281
- raise
1282
-
1283
- def _apply_post_processor(self, action_key: str, raw_data: Any) -> Any:
1284
- """Apply post-processor for the given action if defined."""
1285
- if hasattr(self, "post_processors") and isinstance(self.post_processors, dict):
1286
- processor_func = self.post_processors.get(action_key)
1287
- if processor_func and callable(processor_func):
1288
- try:
1289
- return processor_func(raw_data)
1290
- except (TypeError, ValueError, KeyError) as e:
1291
- logger.error(f"Error in post-processor for {action_key}: {e} (Exception type: {type(e).__name__})")
1292
- return raw_data
1293
-
1294
- return raw_data
1295
-
1296
- def set_default_tools(self):
1297
- """Set the default tools."""