flowent 0.0.5 → 0.0.7

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 (265) hide show
  1. package/README.md +1 -1
  2. package/backend/README.md +1 -1
  3. package/backend/pyproject.toml +1 -1
  4. package/backend/src/flowent/__pycache__/__init__.cpython-313.pyc +0 -0
  5. package/backend/src/flowent/__pycache__/_version.cpython-313.pyc +0 -0
  6. package/backend/src/flowent/__pycache__/access.cpython-313.pyc +0 -0
  7. package/backend/src/flowent/__pycache__/agent.cpython-313.pyc +0 -0
  8. package/backend/src/flowent/__pycache__/assistant_commands.cpython-313.pyc +0 -0
  9. package/backend/src/flowent/__pycache__/cli.cpython-313.pyc +0 -0
  10. package/backend/src/flowent/__pycache__/config.cpython-313.pyc +0 -0
  11. package/backend/src/flowent/__pycache__/events.cpython-313.pyc +0 -0
  12. package/backend/src/flowent/__pycache__/graph_runtime.cpython-313.pyc +0 -0
  13. package/backend/src/flowent/__pycache__/graph_service.cpython-313.pyc +0 -0
  14. package/backend/src/flowent/__pycache__/image_assets.cpython-313.pyc +0 -0
  15. package/backend/src/flowent/__pycache__/logging.cpython-313.pyc +0 -0
  16. package/backend/src/flowent/__pycache__/main.cpython-313.pyc +0 -0
  17. package/backend/src/flowent/__pycache__/model_metadata.cpython-313.pyc +0 -0
  18. package/backend/src/flowent/__pycache__/network.cpython-313.pyc +0 -0
  19. package/backend/src/flowent/__pycache__/observability_service.cpython-313.pyc +0 -0
  20. package/backend/src/flowent/__pycache__/registry.cpython-313.pyc +0 -0
  21. package/backend/src/flowent/__pycache__/role_management.cpython-313.pyc +0 -0
  22. package/backend/src/flowent/__pycache__/runtime.cpython-313.pyc +0 -0
  23. package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
  24. package/backend/src/flowent/__pycache__/security.cpython-313.pyc +0 -0
  25. package/backend/src/flowent/__pycache__/settings.cpython-313.pyc +0 -0
  26. package/backend/src/flowent/__pycache__/settings_management.cpython-313.pyc +0 -0
  27. package/backend/src/flowent/__pycache__/state_db.cpython-313.pyc +0 -0
  28. package/backend/src/flowent/__pycache__/workspace_store.cpython-313.pyc +0 -0
  29. package/backend/src/flowent/agent.py +91 -8
  30. package/backend/src/flowent/channels/__pycache__/__init__.cpython-313.pyc +0 -0
  31. package/backend/src/flowent/channels/__pycache__/telegram.cpython-313.pyc +0 -0
  32. package/backend/src/flowent/graph_service.py +3 -110
  33. package/backend/src/flowent/models/__pycache__/__init__.cpython-313.pyc +0 -0
  34. package/backend/src/flowent/models/__pycache__/agent.cpython-313.pyc +0 -0
  35. package/backend/src/flowent/models/__pycache__/base.cpython-313.pyc +0 -0
  36. package/backend/src/flowent/models/__pycache__/blueprint.cpython-313.pyc +0 -0
  37. package/backend/src/flowent/models/__pycache__/content.cpython-313.pyc +0 -0
  38. package/backend/src/flowent/models/__pycache__/delta.cpython-313.pyc +0 -0
  39. package/backend/src/flowent/models/__pycache__/event.cpython-313.pyc +0 -0
  40. package/backend/src/flowent/models/__pycache__/graph.cpython-313.pyc +0 -0
  41. package/backend/src/flowent/models/__pycache__/history.cpython-313.pyc +0 -0
  42. package/backend/src/flowent/models/__pycache__/llm.cpython-313.pyc +0 -0
  43. package/backend/src/flowent/models/__pycache__/message.cpython-313.pyc +0 -0
  44. package/backend/src/flowent/models/__pycache__/tab.cpython-313.pyc +0 -0
  45. package/backend/src/flowent/models/__pycache__/todo.cpython-313.pyc +0 -0
  46. package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  47. package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
  48. package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
  49. package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  50. package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
  51. package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
  52. package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
  53. package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
  54. package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
  55. package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
  56. package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
  57. package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
  58. package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
  59. package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
  60. package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
  61. package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
  62. package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
  63. package/backend/src/flowent/role_management.py +9 -6
  64. package/backend/src/flowent/routes/__init__.py +0 -2
  65. package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
  66. package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
  67. package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
  68. package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
  69. package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
  70. package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
  71. package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
  72. package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
  73. package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
  74. package/backend/src/flowent/routes/__pycache__/settings.cpython-313.pyc +0 -0
  75. package/backend/src/flowent/routes/__pycache__/tabs.cpython-313.pyc +0 -0
  76. package/backend/src/flowent/routes/__pycache__/ws.cpython-313.pyc +0 -0
  77. package/backend/src/flowent/routes/assistant.py +3 -0
  78. package/backend/src/flowent/routes/nodes.py +11 -1
  79. package/backend/src/flowent/routes/settings.py +169 -118
  80. package/backend/src/flowent/routes/tabs.py +0 -12
  81. package/backend/src/flowent/runtime.py +0 -5
  82. package/backend/src/flowent/security.py +1 -21
  83. package/backend/src/flowent/settings.py +15 -421
  84. package/backend/src/flowent/settings_management.py +260 -164
  85. package/backend/src/flowent/state_db.py +2 -14
  86. package/backend/src/flowent/static/assets/AssistantPage-BW7XAd9I.js +1 -0
  87. package/backend/src/flowent/static/assets/ChannelsPage-tCJHgt6m.js +1 -0
  88. package/backend/src/flowent/static/assets/{PageScaffold-DteOA8V7.js → PageScaffold-f6g2l7XN.js} +1 -1
  89. package/backend/src/flowent/static/assets/PromptsPage-C3Sxn2D7.js +1 -0
  90. package/backend/src/flowent/static/assets/ProvidersPage-BfmdXmNt.js +3 -0
  91. package/backend/src/flowent/static/assets/RolesPage-DET8wO4r.js +1 -0
  92. package/backend/src/flowent/static/assets/SettingsPage-D-g3deMm.js +3 -0
  93. package/backend/src/flowent/static/assets/ToolsPage-CDmtE2g4.js +1 -0
  94. package/backend/src/flowent/static/assets/WorkspacePage-AZsJ0sD0.js +3 -0
  95. package/backend/src/flowent/static/assets/WorkspacePanels-CteCjolX.js +1 -0
  96. package/backend/src/flowent/static/assets/{alert-dialog-DIBUCmqM.js → alert-dialog-Duorp_S-.js} +1 -1
  97. package/backend/src/flowent/static/assets/{dialog-BOvHIBrg.js → dialog-C3ixjGjN.js} +1 -1
  98. package/backend/src/flowent/static/assets/index--o_0fv0N.css +1 -0
  99. package/backend/src/flowent/static/assets/index-C9HuekJm.js +10 -0
  100. package/backend/src/flowent/static/assets/{modelParams-DcEhGnu0.js → modelParams-DmnF2hwR.js} +1 -1
  101. package/backend/src/flowent/static/assets/providerTypes-DT3Ahwl_.js +1 -0
  102. package/backend/src/flowent/static/assets/roles-CuRT_chR.js +1 -0
  103. package/{dist/frontend/assets/select-D9SwnlXF.js → backend/src/flowent/static/assets/select-DCfeNu-F.js} +1 -1
  104. package/backend/src/flowent/static/assets/surface-pWwG5ogx.js +1 -0
  105. package/backend/src/flowent/static/assets/{ui-vendor-UazN8rcv.js → ui-vendor-C5pJa8N7.js} +15 -15
  106. package/backend/src/flowent/static/assets/useAppRoute-FgSHBKhV.js +1 -0
  107. package/backend/src/flowent/static/index.html +3 -3
  108. package/backend/src/flowent/tools/__init__.py +2 -101
  109. package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  110. package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
  111. package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
  112. package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
  113. package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
  114. package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
  115. package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
  116. package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
  117. package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
  118. package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
  119. package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
  120. package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
  121. package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
  122. package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
  123. package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
  124. package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
  125. package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
  126. package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
  127. package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
  128. package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
  129. package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
  130. package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
  131. package/backend/src/flowent/tools/list_roles.py +2 -9
  132. package/backend/src/flowent/tools/manage_settings.py +134 -172
  133. package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  134. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  135. package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  136. package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
  137. package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
  138. package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
  139. package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
  140. package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
  141. package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
  142. package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
  143. package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
  144. package/backend/tests/integration/api/test_assistant_api.py +68 -0
  145. package/backend/tests/integration/api/test_meta_api.py +0 -1
  146. package/backend/tests/integration/api/test_nodes_api.py +73 -8
  147. package/backend/tests/integration/api/test_tabs_api.py +0 -114
  148. package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
  149. package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  150. package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  151. package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
  152. package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
  153. package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
  154. package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
  155. package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  156. package/backend/tests/unit/agent/test_agent_public_api.py +0 -15
  157. package/backend/tests/unit/agent/test_agent_runtime.py +148 -2
  158. package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
  159. package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  160. package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
  161. package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  162. package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
  163. package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
  164. package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  165. package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
  166. package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
  167. package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
  168. package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  169. package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
  170. package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  171. package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  172. package/backend/tests/unit/routes/test_prompts_routes.py +0 -22
  173. package/backend/tests/unit/routes/test_roles_routes.py +6 -2
  174. package/backend/tests/unit/routes/test_settings_routes.py +0 -19
  175. package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  176. package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  177. package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
  178. package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
  179. package/backend/tests/unit/settings/test_settings_roles.py +3 -51
  180. package/backend/tests/unit/test_cli.py +0 -22
  181. package/backend/tests/unit/test_state_sqlite_storage.py +27 -99
  182. package/backend/tests/unit/test_workspace_store.py +0 -3
  183. package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  184. package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  185. package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  186. package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  187. package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  188. package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  189. package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  190. package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  191. package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  192. package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  193. package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  194. package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  195. package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  196. package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
  197. package/backend/tests/unit/tools/test_create_agent_tool.py +0 -32
  198. package/backend/tests/unit/tools/test_manage_prompts_tool.py +5 -30
  199. package/backend/tests/unit/tools/test_tool_registry.py +45 -40
  200. package/backend/uv.lock +1 -1
  201. package/dist/frontend/assets/AssistantPage-BW7XAd9I.js +1 -0
  202. package/dist/frontend/assets/ChannelsPage-tCJHgt6m.js +1 -0
  203. package/dist/frontend/assets/{PageScaffold-DteOA8V7.js → PageScaffold-f6g2l7XN.js} +1 -1
  204. package/dist/frontend/assets/PromptsPage-C3Sxn2D7.js +1 -0
  205. package/dist/frontend/assets/ProvidersPage-BfmdXmNt.js +3 -0
  206. package/dist/frontend/assets/RolesPage-DET8wO4r.js +1 -0
  207. package/dist/frontend/assets/SettingsPage-D-g3deMm.js +3 -0
  208. package/dist/frontend/assets/ToolsPage-CDmtE2g4.js +1 -0
  209. package/dist/frontend/assets/WorkspacePage-AZsJ0sD0.js +3 -0
  210. package/dist/frontend/assets/WorkspacePanels-CteCjolX.js +1 -0
  211. package/dist/frontend/assets/{alert-dialog-DIBUCmqM.js → alert-dialog-Duorp_S-.js} +1 -1
  212. package/dist/frontend/assets/{dialog-BOvHIBrg.js → dialog-C3ixjGjN.js} +1 -1
  213. package/dist/frontend/assets/index--o_0fv0N.css +1 -0
  214. package/dist/frontend/assets/index-C9HuekJm.js +10 -0
  215. package/dist/frontend/assets/{modelParams-DcEhGnu0.js → modelParams-DmnF2hwR.js} +1 -1
  216. package/dist/frontend/assets/providerTypes-DT3Ahwl_.js +1 -0
  217. package/dist/frontend/assets/roles-CuRT_chR.js +1 -0
  218. package/{backend/src/flowent/static/assets/select-D9SwnlXF.js → dist/frontend/assets/select-DCfeNu-F.js} +1 -1
  219. package/dist/frontend/assets/surface-pWwG5ogx.js +1 -0
  220. package/dist/frontend/assets/{ui-vendor-UazN8rcv.js → ui-vendor-C5pJa8N7.js} +15 -15
  221. package/dist/frontend/assets/useAppRoute-FgSHBKhV.js +1 -0
  222. package/dist/frontend/index.html +3 -3
  223. package/package.json +1 -1
  224. package/backend/src/flowent/__pycache__/mcp_service.cpython-313.pyc +0 -0
  225. package/backend/src/flowent/mcp_service.py +0 -1918
  226. package/backend/src/flowent/routes/__pycache__/mcp.cpython-313.pyc +0 -0
  227. package/backend/src/flowent/routes/mcp.py +0 -125
  228. package/backend/src/flowent/static/assets/AssistantPage-VBohhz4d.js +0 -1
  229. package/backend/src/flowent/static/assets/ChannelsPage-CIydPZA_.js +0 -1
  230. package/backend/src/flowent/static/assets/McpPage-CHPm2TPY.js +0 -7
  231. package/backend/src/flowent/static/assets/PromptsPage-CSmJ3sZg.js +0 -1
  232. package/backend/src/flowent/static/assets/ProvidersPage-sl2jeG4e.js +0 -3
  233. package/backend/src/flowent/static/assets/RolesPage-DCe7W6Km.js +0 -1
  234. package/backend/src/flowent/static/assets/SettingsPage-Bix9e63E.js +0 -3
  235. package/backend/src/flowent/static/assets/ToolsPage-favNkj5C.js +0 -1
  236. package/backend/src/flowent/static/assets/WorkspaceCommandDialog-DRS6wiD6.js +0 -1
  237. package/backend/src/flowent/static/assets/WorkspacePage-KuaDjt_D.js +0 -3
  238. package/backend/src/flowent/static/assets/WorkspacePanels-BZxBw8M5.js +0 -1
  239. package/backend/src/flowent/static/assets/datetime-eJqd0V2S.js +0 -1
  240. package/backend/src/flowent/static/assets/index-Biio-CoI.js +0 -10
  241. package/backend/src/flowent/static/assets/index-CmQvO7sl.css +0 -1
  242. package/backend/src/flowent/static/assets/roles-BbIEIMeG.js +0 -1
  243. package/backend/src/flowent/static/assets/surface-Bzr1FRG4.js +0 -1
  244. package/backend/src/flowent/static/assets/triState-DgLlKdRR.js +0 -1
  245. package/backend/src/flowent/tools/__pycache__/mcp.cpython-313.pyc +0 -0
  246. package/backend/src/flowent/tools/mcp.py +0 -199
  247. package/backend/tests/integration/api/__pycache__/test_mcp_api.cpython-313-pytest-9.0.3.pyc +0 -0
  248. package/backend/tests/integration/api/test_mcp_api.py +0 -116
  249. package/dist/frontend/assets/AssistantPage-VBohhz4d.js +0 -1
  250. package/dist/frontend/assets/ChannelsPage-CIydPZA_.js +0 -1
  251. package/dist/frontend/assets/McpPage-CHPm2TPY.js +0 -7
  252. package/dist/frontend/assets/PromptsPage-CSmJ3sZg.js +0 -1
  253. package/dist/frontend/assets/ProvidersPage-sl2jeG4e.js +0 -3
  254. package/dist/frontend/assets/RolesPage-DCe7W6Km.js +0 -1
  255. package/dist/frontend/assets/SettingsPage-Bix9e63E.js +0 -3
  256. package/dist/frontend/assets/ToolsPage-favNkj5C.js +0 -1
  257. package/dist/frontend/assets/WorkspaceCommandDialog-DRS6wiD6.js +0 -1
  258. package/dist/frontend/assets/WorkspacePage-KuaDjt_D.js +0 -3
  259. package/dist/frontend/assets/WorkspacePanels-BZxBw8M5.js +0 -1
  260. package/dist/frontend/assets/datetime-eJqd0V2S.js +0 -1
  261. package/dist/frontend/assets/index-Biio-CoI.js +0 -10
  262. package/dist/frontend/assets/index-CmQvO7sl.css +0 -1
  263. package/dist/frontend/assets/roles-BbIEIMeG.js +0 -1
  264. package/dist/frontend/assets/surface-Bzr1FRG4.js +0 -1
  265. package/dist/frontend/assets/triState-DgLlKdRR.js +0 -1
@@ -2,6 +2,7 @@ from __future__ import annotations
2
2
 
3
3
  import time
4
4
  from copy import deepcopy
5
+ from dataclasses import dataclass
5
6
 
6
7
  from fastapi import APIRouter, HTTPException
7
8
  from loguru import logger
@@ -62,77 +63,15 @@ class UpdateTelegramSettingsRequest(BaseModel):
62
63
  bot_token: str | None = None
63
64
 
64
65
 
65
- @router.post("/api/settings")
66
- async def update_settings(req: UpdateSettingsRequest) -> dict[str, object]:
67
- from flowent.graph_service import sync_assistant_role, sync_tab_leaders
68
- from flowent.providers.gateway import gateway
69
-
70
- source_settings = get_settings()
71
- current = deepcopy(source_settings)
72
- next_access_code: str | None = None
73
- reauth_required = False
66
+ @dataclass(frozen=True, slots=True)
67
+ class AssistantSettingsPatch:
68
+ role_name: str | None = None
69
+ allow_network: object = MISSING
70
+ write_dirs: object = MISSING
74
71
 
75
- if req.access is not None:
76
- raw_new_code = req.access.get("new_code", "")
77
- raw_confirm_code = req.access.get("confirm_code", "")
78
- if raw_new_code is not None and not isinstance(raw_new_code, str):
79
- raise HTTPException(
80
- status_code=400, detail="access.new_code must be a string"
81
- )
82
- if raw_confirm_code is not None and not isinstance(raw_confirm_code, str):
83
- raise HTTPException(
84
- status_code=400,
85
- detail="access.confirm_code must be a string",
86
- )
87
- new_code = raw_new_code if isinstance(raw_new_code, str) else ""
88
- confirm_code = raw_confirm_code if isinstance(raw_confirm_code, str) else ""
89
- if new_code or confirm_code:
90
- if not new_code.strip():
91
- raise HTTPException(
92
- status_code=400,
93
- detail="access.new_code must not be empty",
94
- )
95
- if confirm_code != new_code:
96
- raise HTTPException(
97
- status_code=400,
98
- detail="access.confirm_code must match access.new_code",
99
- )
100
- next_access_code = new_code
101
-
102
- assistant_role_name: str | None = None
103
- assistant_allow_network: object = MISSING
104
- assistant_write_dirs: object = MISSING
105
- if req.assistant is not None:
106
- assistant_unknown_fields = sorted(
107
- set(req.assistant) - {"role_name", "allow_network", "write_dirs"}
108
- )
109
- if assistant_unknown_fields:
110
- raise HTTPException(
111
- status_code=400,
112
- detail=(
113
- "Unknown assistant fields: " + ", ".join(assistant_unknown_fields)
114
- ),
115
- )
116
- if "allow_network" in req.assistant:
117
- assistant_allow_network = req.assistant.get("allow_network")
118
- if "write_dirs" in req.assistant:
119
- assistant_write_dirs = req.assistant.get("write_dirs")
120
- raw_role_name = req.assistant.get("role_name")
121
- if isinstance(raw_role_name, str) and raw_role_name.strip():
122
- assistant_role_name = raw_role_name
123
-
124
- leader_role_name: str | None = None
125
- if req.leader is not None:
126
- raw_role_name = req.leader.get("role_name")
127
- if isinstance(raw_role_name, str) and raw_role_name.strip():
128
- leader_role_name = raw_role_name
129
-
130
- timestamp_format: str | None = None
131
- if req.event_log is not None:
132
- raw_timestamp_format = req.event_log.get("timestamp_format")
133
- if isinstance(raw_timestamp_format, str):
134
- timestamp_format = raw_timestamp_format
135
72
 
73
+ @dataclass(frozen=True, slots=True)
74
+ class ModelSettingsPatch:
136
75
  active_provider_id: str | None = None
137
76
  active_model: str | None = None
138
77
  context_window_tokens: object = MISSING
@@ -146,61 +85,173 @@ async def update_settings(req: UpdateSettingsRequest) -> dict[str, object]:
146
85
  retry_max_delay_seconds: object = MISSING
147
86
  retry_backoff_cap_retries: object = MISSING
148
87
  auto_compact_token_limit: object = MISSING
149
- model_params: object = MISSING
150
- if req.model is not None:
151
- raw_active_provider_id = req.model.get("active_provider_id")
152
- if isinstance(raw_active_provider_id, str):
153
- active_provider_id = raw_active_provider_id
154
- raw_active_model = req.model.get("active_model")
155
- if isinstance(raw_active_model, str):
156
- active_model = raw_active_model
157
- if "context_window_tokens" in req.model:
158
- context_window_tokens = req.model.get("context_window_tokens")
159
- if "input_image" in req.model:
160
- input_image = req.model.get("input_image")
161
- if "output_image" in req.model:
162
- output_image = req.model.get("output_image")
163
- if "structured_output" in req.model:
164
- structured_output = req.model.get("structured_output")
165
- if "timeout_ms" in req.model:
166
- timeout_ms = req.model.get("timeout_ms")
167
- if "retry_policy" in req.model:
168
- retry_policy = req.model.get("retry_policy")
169
- if "max_retries" in req.model:
170
- max_retries = req.model.get("max_retries")
171
- if "retry_initial_delay_seconds" in req.model:
172
- retry_initial_delay_seconds = req.model.get("retry_initial_delay_seconds")
173
- if "retry_max_delay_seconds" in req.model:
174
- retry_max_delay_seconds = req.model.get("retry_max_delay_seconds")
175
- if "retry_backoff_cap_retries" in req.model:
176
- retry_backoff_cap_retries = req.model.get("retry_backoff_cap_retries")
177
- if "auto_compact_token_limit" in req.model:
178
- auto_compact_token_limit = req.model.get("auto_compact_token_limit")
179
- if "params" in req.model:
180
- model_params = req.model.get("params")
88
+ params: object = MISSING
89
+
90
+
91
+ def _extract_access_code_rotation(access: dict[str, object] | None) -> str | None:
92
+ if access is None:
93
+ return None
94
+
95
+ raw_new_code = access.get("new_code", "")
96
+ raw_confirm_code = access.get("confirm_code", "")
97
+ if raw_new_code is not None and not isinstance(raw_new_code, str):
98
+ raise HTTPException(status_code=400, detail="access.new_code must be a string")
99
+ if raw_confirm_code is not None and not isinstance(raw_confirm_code, str):
100
+ raise HTTPException(
101
+ status_code=400,
102
+ detail="access.confirm_code must be a string",
103
+ )
104
+
105
+ new_code = raw_new_code if isinstance(raw_new_code, str) else ""
106
+ confirm_code = raw_confirm_code if isinstance(raw_confirm_code, str) else ""
107
+ if not new_code and not confirm_code:
108
+ return None
109
+ if not new_code.strip():
110
+ raise HTTPException(
111
+ status_code=400,
112
+ detail="access.new_code must not be empty",
113
+ )
114
+ if confirm_code != new_code:
115
+ raise HTTPException(
116
+ status_code=400,
117
+ detail="access.confirm_code must match access.new_code",
118
+ )
119
+ return new_code
120
+
121
+
122
+ def _extract_assistant_settings_patch(
123
+ assistant: dict[str, object] | None,
124
+ ) -> AssistantSettingsPatch:
125
+ if assistant is None:
126
+ return AssistantSettingsPatch()
127
+
128
+ unknown_fields = sorted(
129
+ set(assistant) - {"role_name", "allow_network", "write_dirs"}
130
+ )
131
+ if unknown_fields:
132
+ raise HTTPException(
133
+ status_code=400,
134
+ detail="Unknown assistant fields: " + ", ".join(unknown_fields),
135
+ )
136
+
137
+ raw_role_name = assistant.get("role_name")
138
+ return AssistantSettingsPatch(
139
+ role_name=(
140
+ raw_role_name
141
+ if isinstance(raw_role_name, str) and raw_role_name.strip()
142
+ else None
143
+ ),
144
+ allow_network=(
145
+ assistant.get("allow_network") if "allow_network" in assistant else MISSING
146
+ ),
147
+ write_dirs=assistant.get("write_dirs")
148
+ if "write_dirs" in assistant
149
+ else MISSING,
150
+ )
151
+
152
+
153
+ def _extract_role_name(payload: dict[str, object] | None) -> str | None:
154
+ if payload is None:
155
+ return None
156
+ raw_role_name = payload.get("role_name")
157
+ if isinstance(raw_role_name, str) and raw_role_name.strip():
158
+ return raw_role_name
159
+ return None
160
+
161
+
162
+ def _extract_timestamp_format(payload: dict[str, object] | None) -> str | None:
163
+ if payload is None:
164
+ return None
165
+ raw_timestamp_format = payload.get("timestamp_format")
166
+ return raw_timestamp_format if isinstance(raw_timestamp_format, str) else None
167
+
168
+
169
+ def _extract_model_settings_patch(
170
+ model: dict[str, object] | None,
171
+ ) -> ModelSettingsPatch:
172
+ if model is None:
173
+ return ModelSettingsPatch()
174
+
175
+ raw_active_provider_id = model.get("active_provider_id")
176
+ raw_active_model = model.get("active_model")
177
+ return ModelSettingsPatch(
178
+ active_provider_id=(
179
+ raw_active_provider_id if isinstance(raw_active_provider_id, str) else None
180
+ ),
181
+ active_model=raw_active_model if isinstance(raw_active_model, str) else None,
182
+ context_window_tokens=(
183
+ model.get("context_window_tokens")
184
+ if "context_window_tokens" in model
185
+ else MISSING
186
+ ),
187
+ input_image=model.get("input_image") if "input_image" in model else MISSING,
188
+ output_image=model.get("output_image") if "output_image" in model else MISSING,
189
+ structured_output=(
190
+ model.get("structured_output") if "structured_output" in model else MISSING
191
+ ),
192
+ timeout_ms=model.get("timeout_ms") if "timeout_ms" in model else MISSING,
193
+ retry_policy=model.get("retry_policy") if "retry_policy" in model else MISSING,
194
+ max_retries=model.get("max_retries") if "max_retries" in model else MISSING,
195
+ retry_initial_delay_seconds=(
196
+ model.get("retry_initial_delay_seconds")
197
+ if "retry_initial_delay_seconds" in model
198
+ else MISSING
199
+ ),
200
+ retry_max_delay_seconds=(
201
+ model.get("retry_max_delay_seconds")
202
+ if "retry_max_delay_seconds" in model
203
+ else MISSING
204
+ ),
205
+ retry_backoff_cap_retries=(
206
+ model.get("retry_backoff_cap_retries")
207
+ if "retry_backoff_cap_retries" in model
208
+ else MISSING
209
+ ),
210
+ auto_compact_token_limit=(
211
+ model.get("auto_compact_token_limit")
212
+ if "auto_compact_token_limit" in model
213
+ else MISSING
214
+ ),
215
+ params=model.get("params") if "params" in model else MISSING,
216
+ )
217
+
218
+
219
+ @router.post("/api/settings")
220
+ async def update_settings(req: UpdateSettingsRequest) -> dict[str, object]:
221
+ from flowent.graph_service import sync_assistant_role, sync_tab_leaders
222
+ from flowent.providers.gateway import gateway
223
+
224
+ source_settings = get_settings()
225
+ current = deepcopy(source_settings)
226
+ next_access_code = _extract_access_code_rotation(req.access)
227
+ reauth_required = False
228
+ assistant_patch = _extract_assistant_settings_patch(req.assistant)
229
+ leader_role_name = _extract_role_name(req.leader)
230
+ timestamp_format = _extract_timestamp_format(req.event_log)
231
+ model_patch = _extract_model_settings_patch(req.model)
181
232
 
182
233
  try:
183
234
  resolved = resolve_settings_update(
184
235
  current,
185
236
  working_dir=req.working_dir,
186
- assistant_role_name=assistant_role_name,
187
- assistant_allow_network=assistant_allow_network,
188
- assistant_write_dirs=assistant_write_dirs,
237
+ assistant_role_name=assistant_patch.role_name,
238
+ assistant_allow_network=assistant_patch.allow_network,
239
+ assistant_write_dirs=assistant_patch.write_dirs,
189
240
  leader_role_name=leader_role_name,
190
- active_provider_id=active_provider_id,
191
- active_model=active_model,
192
- context_window_tokens=context_window_tokens,
193
- input_image=input_image,
194
- output_image=output_image,
195
- structured_output=structured_output,
196
- max_retries=max_retries,
197
- retry_policy=retry_policy,
198
- timeout_ms=timeout_ms,
199
- retry_initial_delay_seconds=retry_initial_delay_seconds,
200
- retry_max_delay_seconds=retry_max_delay_seconds,
201
- retry_backoff_cap_retries=retry_backoff_cap_retries,
202
- auto_compact_token_limit=auto_compact_token_limit,
203
- model_params=model_params,
241
+ active_provider_id=model_patch.active_provider_id,
242
+ active_model=model_patch.active_model,
243
+ context_window_tokens=model_patch.context_window_tokens,
244
+ input_image=model_patch.input_image,
245
+ output_image=model_patch.output_image,
246
+ structured_output=model_patch.structured_output,
247
+ max_retries=model_patch.max_retries,
248
+ retry_policy=model_patch.retry_policy,
249
+ timeout_ms=model_patch.timeout_ms,
250
+ retry_initial_delay_seconds=model_patch.retry_initial_delay_seconds,
251
+ retry_max_delay_seconds=model_patch.retry_max_delay_seconds,
252
+ retry_backoff_cap_retries=model_patch.retry_backoff_cap_retries,
253
+ auto_compact_token_limit=model_patch.auto_compact_token_limit,
254
+ model_params=model_patch.params,
204
255
  timestamp_format=timestamp_format,
205
256
  )
206
257
  except ValueError as exc:
@@ -13,7 +13,6 @@ from flowent.graph_service import (
13
13
  delete_agent_node,
14
14
  delete_edge,
15
15
  delete_tab,
16
- duplicate_tab,
17
16
  list_node_connection_ids,
18
17
  list_tab_edges,
19
18
  list_workflow_nodes,
@@ -125,17 +124,6 @@ async def create_workflow_route(req: CreateTabRequest) -> dict[str, object]:
125
124
  return serialize_tab_summary(tab)
126
125
 
127
126
 
128
- @router.post("/api/workflows/{tab_id}/duplicate")
129
- async def duplicate_workflow_route(tab_id: str) -> dict[str, object]:
130
- duplicated, error = duplicate_tab(tab_id=tab_id)
131
- if error is not None or duplicated is None:
132
- raise HTTPException(
133
- status_code=404 if error and error.endswith("not found") else 400,
134
- detail=error or "Failed to duplicate workflow",
135
- )
136
- return serialize_tab_summary(duplicated)
137
-
138
-
139
127
  @router.post("/api/workflows/{tab_id}/activate")
140
128
  async def activate_workflow_route(tab_id: str) -> dict[str, object]:
141
129
  updated, errors, error = activate_tab(tab_id=tab_id, actor_id=tab_id)
@@ -50,7 +50,6 @@ def bootstrap_runtime() -> None:
50
50
  ensure_tab_leaders,
51
51
  resolve_effective_permissions_for_node_record,
52
52
  )
53
- from flowent.mcp_service import mcp_service
54
53
  from flowent.models import AgentState, NodeConfig, NodeType
55
54
  from flowent.settings import (
56
55
  ensure_builtin_roles,
@@ -60,13 +59,11 @@ def bootstrap_runtime() -> None:
60
59
  from flowent.workspace_store import workspace_store
61
60
 
62
61
  workspace_store.reset_cache()
63
- mcp_service.clear_runtime_state()
64
62
  settings = get_settings()
65
63
  settings_changed = ensure_builtin_roles(settings)
66
64
  generated_access_code = ensure_access_bootstrap(settings)
67
65
  if settings_changed or generated_access_code is not None:
68
66
  save_settings(settings)
69
- mcp_service.bootstrap()
70
67
  assistant_tools = build_assistant_tools(settings=settings)
71
68
 
72
69
  assistant_record = next(
@@ -146,12 +143,10 @@ def bootstrap_runtime() -> None:
146
143
 
147
144
 
148
145
  def shutdown_runtime(timeout: float = SYSTEM_NODE_TIMEOUT) -> None:
149
- from flowent.mcp_service import mcp_service
150
146
  from flowent.models import NodeType
151
147
 
152
148
  logger.info("Shutting down runtime")
153
149
  _stop_telegram_channel()
154
- mcp_service.clear_runtime_state()
155
150
  persistent_agents = []
156
151
  for agent in registry.get_all():
157
152
  if agent.node_type == NodeType.ASSISTANT or agent.config.tab_id:
@@ -12,7 +12,6 @@ def authorize(tool_name: str, agent: Agent, args: dict[str, Any]) -> str | None:
12
12
  from flowent.graph_service import resolve_effective_permissions_for_agent
13
13
  from flowent.models import NodeType
14
14
  from flowent.tools import (
15
- is_assistant_only_mcp_tool_name,
16
15
  is_assistant_only_tool_name,
17
16
  )
18
17
 
@@ -22,26 +21,7 @@ def authorize(tool_name: str, agent: Agent, args: dict[str, Any]) -> str | None:
22
21
  allow_network, write_dirs = resolve_effective_permissions_for_agent(agent)
23
22
 
24
23
  if tool_name.startswith("mcp__"):
25
- from flowent.mcp_service import mcp_service
26
- from flowent.settings import find_mcp_server, get_settings
27
-
28
- descriptor = mcp_service.get_dynamic_tool_descriptor(tool_name)
29
- if descriptor is None:
30
- return f"MCP tool not found: {tool_name}"
31
- if agent.node_type != NodeType.ASSISTANT and is_assistant_only_mcp_tool_name(
32
- descriptor.tool_name
33
- ):
34
- return "Ask the Assistant to manage workflows or settings"
35
- server = find_mcp_server(get_settings(), descriptor.server_name)
36
- if (
37
- server is not None
38
- and server.transport == "streamable_http"
39
- and not allow_network
40
- ):
41
- return "Network access is disabled for this workflow"
42
- if descriptor.open_world_hint and not allow_network:
43
- return "Network access is disabled for this workflow"
44
- return None
24
+ return f"Tool not found: {tool_name}"
45
25
 
46
26
  if tool_name == "edit":
47
27
  if not write_dirs: