flowent 0.0.4 → 0.0.6

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 (311) hide show
  1. package/README.md +1 -1
  2. package/backend/README.md +74 -0
  3. package/backend/pyproject.toml +2 -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__/mcp_service.cpython-313.pyc +0 -0
  18. package/backend/src/flowent/__pycache__/model_metadata.cpython-313.pyc +0 -0
  19. package/backend/src/flowent/__pycache__/network.cpython-313.pyc +0 -0
  20. package/backend/src/flowent/__pycache__/{stats_service.cpython-313.pyc → observability_service.cpython-313.pyc} +0 -0
  21. package/backend/src/flowent/__pycache__/registry.cpython-313.pyc +0 -0
  22. package/backend/src/flowent/__pycache__/role_management.cpython-313.pyc +0 -0
  23. package/backend/src/flowent/__pycache__/runtime.cpython-313.pyc +0 -0
  24. package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
  25. package/backend/src/flowent/__pycache__/security.cpython-313.pyc +0 -0
  26. package/backend/src/flowent/__pycache__/settings.cpython-313.pyc +0 -0
  27. package/backend/src/flowent/__pycache__/settings_management.cpython-313.pyc +0 -0
  28. package/backend/src/flowent/__pycache__/state_db.cpython-313.pyc +0 -0
  29. package/backend/src/flowent/__pycache__/workspace_store.cpython-313.pyc +0 -0
  30. package/backend/src/flowent/agent.py +364 -52
  31. package/backend/src/flowent/assistant_commands.py +31 -22
  32. package/backend/src/flowent/channels/__pycache__/__init__.cpython-313.pyc +0 -0
  33. package/backend/src/flowent/channels/__pycache__/telegram.cpython-313.pyc +0 -0
  34. package/backend/src/flowent/channels/telegram.py +4 -4
  35. package/backend/src/flowent/graph_service.py +1307 -145
  36. package/backend/src/flowent/mcp_service.py +21 -7
  37. package/backend/src/flowent/model_metadata.py +4 -0
  38. package/backend/src/flowent/models/__init__.py +6 -2
  39. package/backend/src/flowent/models/__pycache__/__init__.cpython-313.pyc +0 -0
  40. package/backend/src/flowent/models/__pycache__/agent.cpython-313.pyc +0 -0
  41. package/backend/src/flowent/models/__pycache__/base.cpython-313.pyc +0 -0
  42. package/backend/src/flowent/models/__pycache__/blueprint.cpython-313.pyc +0 -0
  43. package/backend/src/flowent/models/__pycache__/content.cpython-313.pyc +0 -0
  44. package/backend/src/flowent/models/__pycache__/delta.cpython-313.pyc +0 -0
  45. package/backend/src/flowent/models/__pycache__/event.cpython-313.pyc +0 -0
  46. package/backend/src/flowent/models/__pycache__/graph.cpython-313.pyc +0 -0
  47. package/backend/src/flowent/models/__pycache__/history.cpython-313.pyc +0 -0
  48. package/backend/src/flowent/models/__pycache__/llm.cpython-313.pyc +0 -0
  49. package/backend/src/flowent/models/__pycache__/message.cpython-313.pyc +0 -0
  50. package/backend/src/flowent/models/__pycache__/tab.cpython-313.pyc +0 -0
  51. package/backend/src/flowent/models/__pycache__/todo.cpython-313.pyc +0 -0
  52. package/backend/src/flowent/models/agent.py +1 -0
  53. package/backend/src/flowent/models/graph.py +44 -9
  54. package/backend/src/flowent/models/history.py +73 -15
  55. package/backend/src/flowent/models/llm.py +1 -0
  56. package/backend/src/flowent/models/message.py +6 -0
  57. package/backend/src/flowent/models/tab.py +38 -1
  58. package/backend/src/flowent/{stats_service.py → observability_service.py} +4 -4
  59. package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  60. package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
  61. package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
  62. package/backend/src/flowent/prompts/common.py +2 -2
  63. package/backend/src/flowent/prompts/steward.py +2 -2
  64. package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  65. package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
  66. package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
  67. package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
  68. package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
  69. package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
  70. package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
  71. package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
  72. package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
  73. package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
  74. package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
  75. package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
  76. package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
  77. package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
  78. package/backend/src/flowent/providers/configuration.py +7 -0
  79. package/backend/src/flowent/role_management.py +12 -0
  80. package/backend/src/flowent/routes/__init__.py +0 -2
  81. package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
  82. package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
  83. package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
  84. package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
  85. package/backend/src/flowent/routes/__pycache__/mcp.cpython-313.pyc +0 -0
  86. package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
  87. package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
  88. package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
  89. package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
  90. package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
  91. package/backend/src/flowent/routes/__pycache__/settings.cpython-313.pyc +0 -0
  92. package/backend/src/flowent/routes/__pycache__/tabs.cpython-313.pyc +0 -0
  93. package/backend/src/flowent/routes/__pycache__/ws.cpython-313.pyc +0 -0
  94. package/backend/src/flowent/routes/assistant.py +4 -4
  95. package/backend/src/flowent/routes/nodes.py +54 -6
  96. package/backend/src/flowent/routes/providers_route.py +1 -0
  97. package/backend/src/flowent/routes/roles.py +1 -1
  98. package/backend/src/flowent/routes/settings.py +4 -0
  99. package/backend/src/flowent/routes/tabs.py +29 -11
  100. package/backend/src/flowent/runtime.py +7 -30
  101. package/backend/src/flowent/security.py +23 -8
  102. package/backend/src/flowent/settings.py +56 -5
  103. package/backend/src/flowent/settings_management.py +12 -0
  104. package/backend/src/flowent/static/assets/AssistantPage-VBohhz4d.js +1 -0
  105. package/backend/src/flowent/static/assets/ChannelsPage-CIydPZA_.js +1 -0
  106. package/backend/src/flowent/static/assets/McpPage-CHPm2TPY.js +7 -0
  107. package/backend/src/flowent/static/assets/PageScaffold-DteOA8V7.js +1 -0
  108. package/backend/src/flowent/static/assets/PromptsPage-CSmJ3sZg.js +1 -0
  109. package/backend/src/flowent/static/assets/ProvidersPage-sl2jeG4e.js +3 -0
  110. package/backend/src/flowent/static/assets/RolesPage-DCe7W6Km.js +1 -0
  111. package/backend/src/flowent/static/assets/SettingsPage-Bix9e63E.js +3 -0
  112. package/backend/src/flowent/static/assets/ToolsPage-favNkj5C.js +1 -0
  113. package/backend/src/flowent/static/assets/WorkspaceCommandDialog-DRS6wiD6.js +1 -0
  114. package/backend/src/flowent/static/assets/WorkspacePage-KuaDjt_D.js +3 -0
  115. package/backend/src/flowent/static/assets/WorkspacePanels-BZxBw8M5.js +1 -0
  116. package/backend/src/flowent/static/assets/alert-dialog-DIBUCmqM.js +1 -0
  117. package/backend/src/flowent/static/assets/{dialog-BeGSweF6.js → dialog-BOvHIBrg.js} +1 -1
  118. package/backend/src/flowent/static/assets/index-Biio-CoI.js +10 -0
  119. package/backend/src/flowent/static/assets/index-CmQvO7sl.css +1 -0
  120. package/backend/src/flowent/static/assets/modelParams-DcEhGnu0.js +1 -0
  121. package/backend/src/flowent/static/assets/roles-BbIEIMeG.js +1 -0
  122. package/backend/src/flowent/static/assets/select-D9SwnlXF.js +1 -0
  123. package/backend/src/flowent/static/assets/surface-Bzr1FRG4.js +1 -0
  124. package/backend/src/flowent/static/assets/{ui-vendor-Dg9NNnWX.js → ui-vendor-UazN8rcv.js} +15 -15
  125. package/backend/src/flowent/static/index.html +3 -4
  126. package/backend/src/flowent/tools/__init__.py +76 -2
  127. package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  128. package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
  129. package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
  130. package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
  131. package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
  132. package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
  133. package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
  134. package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
  135. package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
  136. package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
  137. package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
  138. package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
  139. package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
  140. package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
  141. package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
  142. package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
  143. package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
  144. package/backend/src/flowent/tools/__pycache__/mcp.cpython-313.pyc +0 -0
  145. package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
  146. package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
  147. package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
  148. package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
  149. package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
  150. package/backend/src/flowent/tools/connect.py +10 -66
  151. package/backend/src/flowent/tools/contacts.py +1 -1
  152. package/backend/src/flowent/tools/create_agent.py +9 -88
  153. package/backend/src/flowent/tools/create_tab.py +7 -5
  154. package/backend/src/flowent/tools/exec.py +3 -2
  155. package/backend/src/flowent/tools/list_roles.py +29 -4
  156. package/backend/src/flowent/tools/list_tabs.py +4 -0
  157. package/backend/src/flowent/tools/list_tools.py +5 -1
  158. package/backend/src/flowent/tools/manage_settings.py +18 -0
  159. package/backend/src/flowent/tools/send.py +21 -3
  160. package/backend/src/flowent/tools/set_permissions.py +21 -6
  161. package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  162. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  163. package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  164. package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
  165. package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
  166. package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
  167. package/backend/tests/integration/api/__pycache__/test_mcp_api.cpython-313-pytest-9.0.3.pyc +0 -0
  168. package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
  169. package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
  170. package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
  171. package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
  172. package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
  173. package/backend/tests/integration/api/test_assistant_api.py +1 -1
  174. package/backend/tests/integration/api/test_nodes_api.py +257 -21
  175. package/backend/tests/integration/api/test_roles_api.py +3 -2
  176. package/backend/tests/integration/api/test_tabs_api.py +312 -11
  177. package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
  178. package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  179. package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  180. package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
  181. package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
  182. package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
  183. package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
  184. package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  185. package/backend/tests/unit/agent/test_agent_public_api.py +162 -71
  186. package/backend/tests/unit/agent/test_agent_runtime.py +285 -69
  187. package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
  188. package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  189. package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
  190. package/backend/tests/unit/prompts/test_prompts.py +3 -2
  191. package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  192. package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
  193. package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
  194. package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  195. package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
  196. package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
  197. package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
  198. package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  199. package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
  200. package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  201. package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  202. package/backend/tests/unit/routes/test_providers_route.py +2 -0
  203. package/backend/tests/unit/routes/test_roles_routes.py +109 -0
  204. package/backend/tests/unit/routes/test_settings_routes.py +4 -0
  205. package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  206. package/backend/tests/unit/runtime/test_bootstrap_runtime.py +8 -18
  207. package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  208. package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
  209. package/backend/tests/unit/security/test_security.py +16 -2
  210. package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
  211. package/backend/tests/unit/settings/test_settings_roles.py +40 -0
  212. package/backend/tests/unit/test_state_sqlite_storage.py +67 -1
  213. package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  214. package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  215. package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  216. package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  217. package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  218. package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  219. package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  220. package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  221. package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  222. package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  223. package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  224. package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  225. package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  226. package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
  227. package/backend/tests/unit/tools/test_connect_tool.py +2 -3
  228. package/backend/tests/unit/tools/test_create_agent_tool.py +9 -97
  229. package/backend/tests/unit/tools/test_delete_tab_tool.py +33 -0
  230. package/backend/tests/unit/tools/test_manage_providers_tool.py +2 -0
  231. package/backend/tests/unit/tools/test_manage_settings_tool.py +3 -0
  232. package/backend/tests/unit/tools/test_set_permissions_tool.py +216 -12
  233. package/backend/tests/unit/tools/test_tool_registry.py +103 -0
  234. package/backend/uv.lock +1 -1
  235. package/dist/frontend/assets/AssistantPage-VBohhz4d.js +1 -0
  236. package/dist/frontend/assets/ChannelsPage-CIydPZA_.js +1 -0
  237. package/dist/frontend/assets/McpPage-CHPm2TPY.js +7 -0
  238. package/dist/frontend/assets/PageScaffold-DteOA8V7.js +1 -0
  239. package/dist/frontend/assets/PromptsPage-CSmJ3sZg.js +1 -0
  240. package/dist/frontend/assets/ProvidersPage-sl2jeG4e.js +3 -0
  241. package/dist/frontend/assets/RolesPage-DCe7W6Km.js +1 -0
  242. package/dist/frontend/assets/SettingsPage-Bix9e63E.js +3 -0
  243. package/dist/frontend/assets/ToolsPage-favNkj5C.js +1 -0
  244. package/dist/frontend/assets/WorkspaceCommandDialog-DRS6wiD6.js +1 -0
  245. package/dist/frontend/assets/WorkspacePage-KuaDjt_D.js +3 -0
  246. package/dist/frontend/assets/WorkspacePanels-BZxBw8M5.js +1 -0
  247. package/dist/frontend/assets/alert-dialog-DIBUCmqM.js +1 -0
  248. package/dist/frontend/assets/{dialog-BeGSweF6.js → dialog-BOvHIBrg.js} +1 -1
  249. package/dist/frontend/assets/index-Biio-CoI.js +10 -0
  250. package/dist/frontend/assets/index-CmQvO7sl.css +1 -0
  251. package/dist/frontend/assets/modelParams-DcEhGnu0.js +1 -0
  252. package/dist/frontend/assets/roles-BbIEIMeG.js +1 -0
  253. package/dist/frontend/assets/select-D9SwnlXF.js +1 -0
  254. package/dist/frontend/assets/surface-Bzr1FRG4.js +1 -0
  255. package/dist/frontend/assets/{ui-vendor-Dg9NNnWX.js → ui-vendor-UazN8rcv.js} +15 -15
  256. package/dist/frontend/index.html +3 -4
  257. package/package.json +3 -3
  258. package/backend/src/flowent/routes/__pycache__/stats.cpython-313.pyc +0 -0
  259. package/backend/src/flowent/routes/stats.py +0 -229
  260. package/backend/src/flowent/static/assets/AssistantPage-B3Xc08AS.js +0 -1
  261. package/backend/src/flowent/static/assets/ChannelsPage-ByLd28xk.js +0 -1
  262. package/backend/src/flowent/static/assets/HomePage-C0hAx9_l.js +0 -3
  263. package/backend/src/flowent/static/assets/McpPage-DkrYLvBv.js +0 -7
  264. package/backend/src/flowent/static/assets/PageScaffold-D4jO9ooX.js +0 -1
  265. package/backend/src/flowent/static/assets/PromptsPage-DWA7rRJd.js +0 -1
  266. package/backend/src/flowent/static/assets/ProvidersPage-PUWT8seJ.js +0 -3
  267. package/backend/src/flowent/static/assets/RolesPage-CqcclGRw.js +0 -1
  268. package/backend/src/flowent/static/assets/SettingsPage-8tS2cJgX.js +0 -3
  269. package/backend/src/flowent/static/assets/StatsPage-BX9khYzu.js +0 -1
  270. package/backend/src/flowent/static/assets/ToolsPage-9Tl9FdeD.js +0 -1
  271. package/backend/src/flowent/static/assets/WorkspaceCommandDialog-CCXxjDL8.js +0 -1
  272. package/backend/src/flowent/static/assets/WorkspacePanels-aMdJ7ZH7.js +0 -1
  273. package/backend/src/flowent/static/assets/alert-dialog-kFYVQ7oX.js +0 -1
  274. package/backend/src/flowent/static/assets/badge-74-3jsCg.js +0 -1
  275. package/backend/src/flowent/static/assets/constants-XUzFf6i1.js +0 -1
  276. package/backend/src/flowent/static/assets/index-BHC1Vhy8.css +0 -1
  277. package/backend/src/flowent/static/assets/index-CL1ALZ3r.js +0 -10
  278. package/backend/src/flowent/static/assets/modelParams-CaHd0903.js +0 -1
  279. package/backend/src/flowent/static/assets/roles-2OLDeTc5.js +0 -1
  280. package/backend/src/flowent/static/assets/select-DL_LPeDj.js +0 -1
  281. package/backend/src/flowent/static/assets/shared-CMxbpLeQ.js +0 -1
  282. package/backend/tests/unit/routes/__pycache__/test_stats_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  283. package/backend/tests/unit/routes/test_stats_routes.py +0 -149
  284. package/dist/frontend/assets/AssistantPage-B3Xc08AS.js +0 -1
  285. package/dist/frontend/assets/ChannelsPage-ByLd28xk.js +0 -1
  286. package/dist/frontend/assets/HomePage-C0hAx9_l.js +0 -3
  287. package/dist/frontend/assets/McpPage-DkrYLvBv.js +0 -7
  288. package/dist/frontend/assets/PageScaffold-D4jO9ooX.js +0 -1
  289. package/dist/frontend/assets/PromptsPage-DWA7rRJd.js +0 -1
  290. package/dist/frontend/assets/ProvidersPage-PUWT8seJ.js +0 -3
  291. package/dist/frontend/assets/RolesPage-CqcclGRw.js +0 -1
  292. package/dist/frontend/assets/SettingsPage-8tS2cJgX.js +0 -3
  293. package/dist/frontend/assets/StatsPage-BX9khYzu.js +0 -1
  294. package/dist/frontend/assets/ToolsPage-9Tl9FdeD.js +0 -1
  295. package/dist/frontend/assets/WorkspaceCommandDialog-CCXxjDL8.js +0 -1
  296. package/dist/frontend/assets/WorkspacePanels-aMdJ7ZH7.js +0 -1
  297. package/dist/frontend/assets/alert-dialog-kFYVQ7oX.js +0 -1
  298. package/dist/frontend/assets/badge-74-3jsCg.js +0 -1
  299. package/dist/frontend/assets/constants-XUzFf6i1.js +0 -1
  300. package/dist/frontend/assets/index-BHC1Vhy8.css +0 -1
  301. package/dist/frontend/assets/index-CL1ALZ3r.js +0 -10
  302. package/dist/frontend/assets/modelParams-CaHd0903.js +0 -1
  303. package/dist/frontend/assets/roles-2OLDeTc5.js +0 -1
  304. package/dist/frontend/assets/select-DL_LPeDj.js +0 -1
  305. package/dist/frontend/assets/shared-CMxbpLeQ.js +0 -1
  306. /package/backend/src/flowent/static/assets/{datetime-m6_O_Ci9.js → datetime-eJqd0V2S.js} +0 -0
  307. /package/backend/src/flowent/static/assets/{markdown-vendor-DVdy_w12.js → markdown-vendor-C9RtvaJh.js} +0 -0
  308. /package/backend/src/flowent/static/assets/{triState-DEr3NkXV.js → triState-DgLlKdRR.js} +0 -0
  309. /package/dist/frontend/assets/{datetime-m6_O_Ci9.js → datetime-eJqd0V2S.js} +0 -0
  310. /package/dist/frontend/assets/{markdown-vendor-DVdy_w12.js → markdown-vendor-C9RtvaJh.js} +0 -0
  311. /package/dist/frontend/assets/{triState-DEr3NkXV.js → triState-DgLlKdRR.js} +0 -0
@@ -178,7 +178,7 @@ def test_compose_system_prompt_injects_set_permissions_guidance_when_tool_presen
178
178
  )
179
179
 
180
180
  assert SET_PERMISSIONS_TOOL_GUIDANCE in result
181
- assert "bound Leader's `allow_network` and `write_dirs`" in result
181
+ assert "target workflow's own `allow_network` and `write_dirs`" in result
182
182
 
183
183
 
184
184
  def test_common_communication_guidance_requires_explicit_target_routing():
@@ -398,7 +398,7 @@ def test_get_system_prompt_reads_conductor_prompt_via_role_system(monkeypatch):
398
398
  )
399
399
  assert ASSISTANT_ONLY_PROMPT not in prompt
400
400
  assert CREATE_AGENT_TOOL_GUIDANCE in prompt
401
- assert LIST_WORKFLOWS_TOOL_GUIDANCE in prompt
401
+ assert LIST_WORKFLOWS_TOOL_GUIDANCE not in prompt
402
402
  assert LIST_ROLES_TOOL_GUIDANCE in prompt
403
403
  assert LIST_TOOLS_TOOL_GUIDANCE in prompt
404
404
  assert "## Tools Available" not in CONDUCTOR_ROLE_SYSTEM_PROMPT
@@ -549,6 +549,7 @@ def test_steward_included_tools_contains_list_roles_and_list_tools():
549
549
  assert "list_tools" in STEWARD_ROLE_INCLUDED_TOOLS
550
550
  assert "connect" not in STEWARD_ROLE_INCLUDED_TOOLS
551
551
  assert "connect" in CONDUCTOR_ROLE_INCLUDED_TOOLS
552
+ assert "list_workflows" not in CONDUCTOR_ROLE_INCLUDED_TOOLS
552
553
  assert "set_permissions" not in CONDUCTOR_ROLE_INCLUDED_TOOLS
553
554
  assert "set_permissions" not in WORKER_ROLE_INCLUDED_TOOLS
554
555
 
@@ -234,6 +234,7 @@ def test_list_provider_models_runs_gateway_in_threadpool(monkeypatch):
234
234
  "context_window_tokens": None,
235
235
  "input_image": False,
236
236
  "output_image": False,
237
+ "structured_output": False,
237
238
  }
238
239
  ]
239
240
  }
@@ -327,6 +328,7 @@ def test_list_provider_models_from_draft_passes_raw_base_url_to_provider(
327
328
  "context_window_tokens": None,
328
329
  "input_image": False,
329
330
  "output_image": False,
331
+ "structured_output": False,
330
332
  }
331
333
  ]
332
334
  }
@@ -15,8 +15,11 @@ from flowent.routes.roles import (
15
15
  from flowent.settings import (
16
16
  CONDUCTOR_ROLE_NAME,
17
17
  DESIGNER_ROLE_NAME,
18
+ STEWARD_ROLE_INCLUDED_TOOLS,
19
+ STEWARD_ROLE_NAME,
18
20
  AssistantSettings,
19
21
  ProviderConfig,
22
+ ProviderModelCatalogEntry,
20
23
  RoleConfig,
21
24
  RoleModelConfig,
22
25
  Settings,
@@ -156,6 +159,33 @@ def test_create_role_uses_name_as_identifier(monkeypatch):
156
159
  assert saved == [["Reviewer"]]
157
160
 
158
161
 
162
+ def test_create_role_filters_assistant_only_tools(monkeypatch):
163
+ settings = Settings()
164
+ monkeypatch.setattr("flowent.routes.roles.get_settings", lambda: settings)
165
+ monkeypatch.setattr("flowent.routes.roles.save_settings", lambda current: None)
166
+
167
+ result = asyncio.run(
168
+ create_role(
169
+ CreateRoleRequest(
170
+ name="Reviewer",
171
+ description="Review code carefully",
172
+ system_prompt="Review code carefully",
173
+ included_tools=[
174
+ "read",
175
+ "create_workflow",
176
+ "delete_workflow",
177
+ "list_workflows",
178
+ "mcp__flowent__list_workflows",
179
+ "manage_settings",
180
+ ],
181
+ )
182
+ )
183
+ )
184
+
185
+ assert result["included_tools"] == ["read"]
186
+ assert settings.roles[0].included_tools == ["read"]
187
+
188
+
159
189
  def test_create_role_rejects_duplicate_name(monkeypatch):
160
190
  settings = Settings(
161
191
  roles=[RoleConfig(name="Reviewer", system_prompt="Review code carefully")]
@@ -231,6 +261,40 @@ def test_update_role_uses_name_path_parameter(monkeypatch):
231
261
  assert saved == [["Architect"]]
232
262
 
233
263
 
264
+ def test_update_role_filters_assistant_only_tools(monkeypatch):
265
+ settings = Settings(
266
+ roles=[
267
+ RoleConfig(
268
+ name="Reviewer",
269
+ description="Review code carefully",
270
+ system_prompt="Review code carefully",
271
+ included_tools=["read"],
272
+ )
273
+ ]
274
+ )
275
+ monkeypatch.setattr("flowent.routes.roles.get_settings", lambda: settings)
276
+ monkeypatch.setattr("flowent.routes.roles.save_settings", lambda current: None)
277
+
278
+ result = asyncio.run(
279
+ update_role(
280
+ "Reviewer",
281
+ UpdateRoleRequest(
282
+ included_tools=[
283
+ "read",
284
+ "create_workflow",
285
+ "delete_workflow",
286
+ "list_workflows",
287
+ "mcp__flowent__list_workflows",
288
+ "manage_roles",
289
+ ],
290
+ ),
291
+ )
292
+ )
293
+
294
+ assert result["included_tools"] == ["read"]
295
+ assert settings.roles[0].included_tools == ["read"]
296
+
297
+
234
298
  def test_update_role_rejects_duplicate_name(monkeypatch):
235
299
  settings = Settings(
236
300
  roles=[
@@ -290,6 +354,51 @@ def test_update_role_rejects_builtin_prompt_change(monkeypatch):
290
354
  )
291
355
 
292
356
 
357
+ def test_update_builtin_steward_role_model_preserves_management_tools(monkeypatch):
358
+ settings = Settings(
359
+ providers=[
360
+ ProviderConfig(
361
+ id="provider-1",
362
+ name="OpenAI",
363
+ type="openai",
364
+ base_url="https://api.openai.com/v1",
365
+ api_key="sk-test",
366
+ models=[
367
+ ProviderModelCatalogEntry(
368
+ model="gpt-4.1-mini",
369
+ )
370
+ ],
371
+ )
372
+ ],
373
+ roles=[
374
+ RoleConfig(
375
+ name=STEWARD_ROLE_NAME,
376
+ description="Assistant role",
377
+ system_prompt="Help coordinate work.",
378
+ included_tools=list(STEWARD_ROLE_INCLUDED_TOOLS),
379
+ )
380
+ ],
381
+ )
382
+
383
+ monkeypatch.setattr("flowent.routes.roles.get_settings", lambda: settings)
384
+ monkeypatch.setattr("flowent.routes.roles.save_settings", lambda current: None)
385
+
386
+ result = asyncio.run(
387
+ update_role(
388
+ STEWARD_ROLE_NAME,
389
+ UpdateRoleRequest(
390
+ model=RoleModelRequest(
391
+ provider_id="provider-1",
392
+ model="gpt-4.1-mini",
393
+ )
394
+ ),
395
+ )
396
+ )
397
+
398
+ assert result["included_tools"] == list(STEWARD_ROLE_INCLUDED_TOOLS)
399
+ assert settings.roles[0].included_tools == list(STEWARD_ROLE_INCLUDED_TOOLS)
400
+
401
+
293
402
  def test_delete_role_uses_name_path_parameter(monkeypatch):
294
403
  settings = Settings(
295
404
  roles=[
@@ -96,6 +96,7 @@ def test_get_settings_bootstrap_returns_related_resources(monkeypatch):
96
96
  "active_model": "",
97
97
  "input_image": None,
98
98
  "output_image": None,
99
+ "structured_output": None,
99
100
  "capabilities": None,
100
101
  "context_window_tokens": None,
101
102
  "resolved_context_window_tokens": None,
@@ -616,6 +617,7 @@ def test_update_settings_accepts_model_metadata_overrides_and_token_limit(
616
617
  "context_window_tokens": 64000,
617
618
  "input_image": True,
618
619
  "output_image": False,
620
+ "structured_output": True,
619
621
  "auto_compact_token_limit": 48000,
620
622
  },
621
623
  )
@@ -625,12 +627,14 @@ def test_update_settings_accepts_model_metadata_overrides_and_token_limit(
625
627
  assert settings.model.context_window_tokens == 64000
626
628
  assert settings.model.input_image is True
627
629
  assert settings.model.output_image is False
630
+ assert settings.model.structured_output is True
628
631
  assert settings.model.auto_compact_token_limit == 48000
629
632
  assert result["settings"]["model"]["context_window_tokens"] == 64000
630
633
  assert result["settings"]["model"]["resolved_context_window_tokens"] == 64000
631
634
  assert result["settings"]["model"]["capabilities"] == {
632
635
  "input_image": True,
633
636
  "output_image": False,
637
+ "structured_output": True,
634
638
  }
635
639
  assert result["settings"]["model"]["auto_compact_token_limit"] == 48000
636
640
  assert saved == [settings]
@@ -5,7 +5,7 @@ import pytest
5
5
 
6
6
  import flowent.settings as settings_module
7
7
  from flowent.agent import Agent
8
- from flowent.models import AgentState, AssistantText, ReceivedMessage, StateEntry
8
+ from flowent.models import AgentState, AssistantText, ReceivedMessage
9
9
  from flowent.registry import registry
10
10
  from flowent.runtime import bootstrap_runtime, shutdown_runtime
11
11
  from flowent.settings import (
@@ -502,10 +502,7 @@ def test_bootstrap_runtime_backfills_state_history_for_restored_nodes(
502
502
  restored = registry.get("node-1")
503
503
  assert restored is not None
504
504
  assert restored.state == AgentState.IDLE
505
- assert any(
506
- isinstance(entry, StateEntry) and entry.state == "idle"
507
- for entry in restored.history
508
- )
505
+ assert restored.history == []
509
506
  finally:
510
507
  registry.reset()
511
508
 
@@ -584,11 +581,8 @@ def test_bootstrap_runtime_restores_active_nodes_as_idle(
584
581
  assert restored.state == AgentState.IDLE
585
582
  assert restored.uuid == "node-1"
586
583
  assert [todo.text for todo in restored.todos] == ["resume me"]
587
- assert any(
588
- isinstance(entry, StateEntry)
589
- and entry.state == "idle"
590
- and entry.reason == "restored"
591
- for entry in restored.history
584
+ assert all(
585
+ entry.__class__.__name__ != "StateEntry" for entry in restored.history
592
586
  )
593
587
  persisted = workspace_store.get_node_record("node-1")
594
588
  assert persisted is not None
@@ -811,11 +805,8 @@ def test_bootstrap_runtime_preserves_error_state_for_restored_nodes(
811
805
  assert restored is not None
812
806
  assert restored.state == AgentState.ERROR
813
807
  assert restored.wait_until_idle(timeout=0.05) is False
814
- assert not any(
815
- isinstance(entry, StateEntry)
816
- and entry.state == "idle"
817
- and entry.reason == "initialized, awaiting first message"
818
- for entry in restored.history
808
+ assert all(
809
+ entry.__class__.__name__ != "StateEntry" for entry in restored.history
819
810
  )
820
811
  persisted = workspace_store.get_node_record("node-1")
821
812
  assert persisted is not None
@@ -990,9 +981,8 @@ def test_shutdown_runtime_keeps_persistent_workspace_nodes_unterminated(
990
981
  persisted = workspace_store.get_node_record("node-1")
991
982
  assert persisted is not None
992
983
  assert persisted.state == AgentState.IDLE
993
- assert not any(
994
- isinstance(entry, StateEntry) and entry.state == "terminated"
995
- for entry in persistent.history
984
+ assert all(
985
+ entry.__class__.__name__ != "StateEntry" for entry in persistent.history
996
986
  )
997
987
 
998
988
  bootstrap_runtime()
@@ -30,7 +30,7 @@ def test_authorize_rejects_edit_when_write_dirs_empty(tmp_path):
30
30
 
31
31
  result = authorize("edit", agent, {"path": str(tmp_path / "blocked.txt")})
32
32
 
33
- assert result == "Write access is disabled for this agent"
33
+ assert result == "Write access is disabled for this workflow"
34
34
 
35
35
 
36
36
  def test_authorize_rejects_edit_outside_write_dirs(tmp_path):
@@ -99,7 +99,7 @@ def test_authorize_rejects_fetch_when_network_disabled():
99
99
 
100
100
  result = authorize("fetch", agent, {"url": "https://example.com"})
101
101
 
102
- assert result == "Network access is disabled for this agent"
102
+ assert result == "Network access is disabled for this workflow"
103
103
 
104
104
 
105
105
  def test_authorize_allows_other_tools_by_default():
@@ -108,3 +108,17 @@ def test_authorize_allows_other_tools_by_default():
108
108
  result = authorize("exec", agent, {"command": "pwd"})
109
109
 
110
110
  assert result is None
111
+
112
+
113
+ def test_authorize_rejects_assistant_only_tools_for_workflow_nodes():
114
+ agent = Agent(
115
+ NodeConfig(
116
+ node_type=NodeType.AGENT,
117
+ role_name="Worker",
118
+ tools=["list_workflows"],
119
+ )
120
+ )
121
+
122
+ result = authorize("list_workflows", agent, {})
123
+
124
+ assert result == "Ask the Assistant to manage workflows or settings"
@@ -465,6 +465,46 @@ def test_load_settings_drops_removed_exit_tool_from_roles(monkeypatch, tmp_path)
465
465
  ]
466
466
 
467
467
 
468
+ def test_load_settings_drops_assistant_only_tools_from_custom_roles(
469
+ monkeypatch,
470
+ tmp_path,
471
+ ):
472
+ settings_file = tmp_path / "settings.json"
473
+ settings_file.write_text(
474
+ json.dumps(
475
+ {
476
+ "event_log": {"timestamp_format": "absolute"},
477
+ "model": {"active_provider_id": "", "active_model": ""},
478
+ "providers": [],
479
+ "roles": [
480
+ {
481
+ "name": "Reviewer",
482
+ "system_prompt": "Review work.",
483
+ "included_tools": [
484
+ "read",
485
+ "create_workflow",
486
+ "delete_workflow",
487
+ "list_workflows",
488
+ "mcp__flowent__list_workflows",
489
+ "manage_settings",
490
+ ],
491
+ }
492
+ ],
493
+ }
494
+ ),
495
+ encoding="utf-8",
496
+ )
497
+
498
+ monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
499
+ monkeypatch.setattr(settings_module, "_cached_settings", None)
500
+
501
+ loaded = settings_module.load_settings()
502
+
503
+ assert loaded.roles[0].included_tools == ["read"]
504
+ persisted = json.loads(settings_file.read_text(encoding="utf-8"))
505
+ assert persisted["roles"][0]["included_tools"] == ["read"]
506
+
507
+
468
508
  def test_load_settings_migrates_legacy_post_prompt_to_custom_post_prompt(
469
509
  monkeypatch, tmp_path
470
510
  ):
@@ -3,8 +3,11 @@ import sqlite3
3
3
  import time
4
4
 
5
5
  import flowent.settings as settings_module
6
+ from flowent.agent import Agent
6
7
  from flowent.image_assets import create_image_asset
7
- from flowent.mcp_service import MCPDiscoverySnapshot, mcp_service
8
+ from flowent.mcp_service import MCPDiscoverySnapshot, MCPToolDescriptor, mcp_service
9
+ from flowent.models import NodeConfig, NodeType
10
+ from flowent.settings import MCPServerConfig, Settings
8
11
 
9
12
  _ONE_PIXEL_PNG = base64.b64decode(
10
13
  "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mP8/x8AAwMCAO+aF9sAAAAASUVORK5CYII="
@@ -91,3 +94,66 @@ def test_mcp_service_restores_persisted_snapshot_and_activity_after_runtime_clea
91
94
  assert restored_activities[0].summary == "Capabilities refreshed"
92
95
  finally:
93
96
  mcp_service.reset()
97
+
98
+
99
+ def test_mcp_service_filters_workflow_management_tools_for_non_assistant(
100
+ monkeypatch,
101
+ tmp_path,
102
+ ):
103
+ settings_file = tmp_path / "settings.json"
104
+ settings_file.write_text("{}", encoding="utf-8")
105
+ monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
106
+ monkeypatch.setattr(settings_module, "_cached_settings", None)
107
+ monkeypatch.setattr(
108
+ "flowent.mcp_service.get_settings",
109
+ lambda: Settings(
110
+ mcp_servers=[
111
+ MCPServerConfig(
112
+ name="flowent",
113
+ transport="stdio",
114
+ )
115
+ ]
116
+ ),
117
+ )
118
+ mcp_service.reset()
119
+
120
+ try:
121
+ mcp_service._set_snapshot(
122
+ MCPDiscoverySnapshot(
123
+ server_name="flowent",
124
+ transport="stdio",
125
+ status="connected",
126
+ auth_status="unsupported",
127
+ tools=[
128
+ MCPToolDescriptor(
129
+ server_name="flowent",
130
+ tool_name="list_workflows",
131
+ fully_qualified_id="mcp__flowent__list_workflows",
132
+ ),
133
+ MCPToolDescriptor(
134
+ server_name="flowent",
135
+ tool_name="search_notes",
136
+ fully_qualified_id="mcp__flowent__search_notes",
137
+ ),
138
+ ],
139
+ )
140
+ )
141
+ worker = Agent(NodeConfig(node_type=NodeType.AGENT), uuid="worker")
142
+ assistant = Agent(NodeConfig(node_type=NodeType.ASSISTANT), uuid="assistant")
143
+
144
+ worker_tools = {
145
+ descriptor.fully_qualified_id
146
+ for descriptor in mcp_service.list_agent_dynamic_tools(worker)
147
+ }
148
+ assistant_tools = {
149
+ descriptor.fully_qualified_id
150
+ for descriptor in mcp_service.list_agent_dynamic_tools(assistant)
151
+ }
152
+
153
+ assert worker_tools == {"mcp__flowent__search_notes"}
154
+ assert assistant_tools == {
155
+ "mcp__flowent__list_workflows",
156
+ "mcp__flowent__search_notes",
157
+ }
158
+ finally:
159
+ mcp_service.reset()
@@ -122,7 +122,6 @@ def test_connect_tool_creates_directed_workflow_edge():
122
122
  "to": right.uuid,
123
123
  "from_port_key": "out",
124
124
  "to_port_key": "in",
125
- "kind": "control",
126
125
  },
127
126
  )
128
127
  )
@@ -132,7 +131,7 @@ def test_connect_tool_creates_directed_workflow_edge():
132
131
  assert result["from_port_key"] == "out"
133
132
  assert result["to_node_id"] == "worker-b"
134
133
  assert result["to_port_key"] == "in"
135
- assert result["kind"] == "control"
134
+ assert "kind" not in result
136
135
  assert left.get_connections_snapshot() == []
137
136
  assert right.get_connections_snapshot() == []
138
137
  stored_edges = workspace_store.list_edges(tab.id)
@@ -191,7 +190,7 @@ def test_connect_tool_resolves_non_agent_workflow_nodes_by_name():
191
190
 
192
191
  assert result["from_node_id"] == "worker-a"
193
192
  assert result["to_node_id"] == "code-a"
194
- assert result["kind"] == "control"
193
+ assert "kind" not in result
195
194
 
196
195
 
197
196
  def test_connect_tool_rejects_leader_endpoints():