flowent 0.0.0 → 0.0.4

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 (494) hide show
  1. package/README.md +70 -10
  2. package/assets/flowent-banner.png +0 -0
  3. package/backend/.python-version +1 -0
  4. package/backend/pyproject.toml +57 -0
  5. package/backend/src/flowent/__init__.py +3 -0
  6. package/backend/src/flowent/__pycache__/__init__.cpython-313.pyc +0 -0
  7. package/backend/src/flowent/__pycache__/_version.cpython-313.pyc +0 -0
  8. package/backend/src/flowent/__pycache__/access.cpython-313.pyc +0 -0
  9. package/backend/src/flowent/__pycache__/agent.cpython-313.pyc +0 -0
  10. package/backend/src/flowent/__pycache__/assistant_commands.cpython-313.pyc +0 -0
  11. package/backend/src/flowent/__pycache__/cli.cpython-313.pyc +0 -0
  12. package/backend/src/flowent/__pycache__/config.cpython-313.pyc +0 -0
  13. package/backend/src/flowent/__pycache__/events.cpython-313.pyc +0 -0
  14. package/backend/src/flowent/__pycache__/graph_runtime.cpython-313.pyc +0 -0
  15. package/backend/src/flowent/__pycache__/graph_service.cpython-313.pyc +0 -0
  16. package/backend/src/flowent/__pycache__/image_assets.cpython-313.pyc +0 -0
  17. package/backend/src/flowent/__pycache__/logging.cpython-313.pyc +0 -0
  18. package/backend/src/flowent/__pycache__/main.cpython-313.pyc +0 -0
  19. package/backend/src/flowent/__pycache__/mcp_service.cpython-313.pyc +0 -0
  20. package/backend/src/flowent/__pycache__/model_metadata.cpython-313.pyc +0 -0
  21. package/backend/src/flowent/__pycache__/network.cpython-313.pyc +0 -0
  22. package/backend/src/flowent/__pycache__/registry.cpython-313.pyc +0 -0
  23. package/backend/src/flowent/__pycache__/role_management.cpython-313.pyc +0 -0
  24. package/backend/src/flowent/__pycache__/runtime.cpython-313.pyc +0 -0
  25. package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
  26. package/backend/src/flowent/__pycache__/security.cpython-313.pyc +0 -0
  27. package/backend/src/flowent/__pycache__/settings.cpython-313.pyc +0 -0
  28. package/backend/src/flowent/__pycache__/settings_management.cpython-313.pyc +0 -0
  29. package/backend/src/flowent/__pycache__/state_db.cpython-313.pyc +0 -0
  30. package/backend/src/flowent/__pycache__/stats_service.cpython-313.pyc +0 -0
  31. package/backend/src/flowent/__pycache__/workspace_store.cpython-313.pyc +0 -0
  32. package/backend/src/flowent/_version.py +7 -0
  33. package/backend/src/flowent/access.py +247 -0
  34. package/backend/src/flowent/agent.py +2808 -0
  35. package/backend/src/flowent/assistant_commands.py +106 -0
  36. package/backend/src/flowent/channels/__init__.py +3 -0
  37. package/backend/src/flowent/channels/__pycache__/__init__.cpython-313.pyc +0 -0
  38. package/backend/src/flowent/channels/__pycache__/telegram.cpython-313.pyc +0 -0
  39. package/backend/src/flowent/channels/telegram.py +615 -0
  40. package/backend/src/flowent/cli.py +85 -0
  41. package/backend/src/flowent/config.py +14 -0
  42. package/backend/src/flowent/dev.py +3 -0
  43. package/backend/src/flowent/events.py +157 -0
  44. package/backend/src/flowent/graph_runtime.py +60 -0
  45. package/backend/src/flowent/graph_service.py +1346 -0
  46. package/backend/src/flowent/image_assets.py +356 -0
  47. package/backend/src/flowent/logging.py +155 -0
  48. package/backend/src/flowent/main.py +124 -0
  49. package/backend/src/flowent/mcp_service.py +1904 -0
  50. package/backend/src/flowent/model_metadata.py +98 -0
  51. package/backend/src/flowent/models/__init__.py +121 -0
  52. package/backend/src/flowent/models/__pycache__/__init__.cpython-313.pyc +0 -0
  53. package/backend/src/flowent/models/__pycache__/agent.cpython-313.pyc +0 -0
  54. package/backend/src/flowent/models/__pycache__/base.cpython-313.pyc +0 -0
  55. package/backend/src/flowent/models/__pycache__/blueprint.cpython-313.pyc +0 -0
  56. package/backend/src/flowent/models/__pycache__/content.cpython-313.pyc +0 -0
  57. package/backend/src/flowent/models/__pycache__/delta.cpython-313.pyc +0 -0
  58. package/backend/src/flowent/models/__pycache__/event.cpython-313.pyc +0 -0
  59. package/backend/src/flowent/models/__pycache__/graph.cpython-313.pyc +0 -0
  60. package/backend/src/flowent/models/__pycache__/history.cpython-313.pyc +0 -0
  61. package/backend/src/flowent/models/__pycache__/llm.cpython-313.pyc +0 -0
  62. package/backend/src/flowent/models/__pycache__/message.cpython-313.pyc +0 -0
  63. package/backend/src/flowent/models/__pycache__/tab.cpython-313.pyc +0 -0
  64. package/backend/src/flowent/models/__pycache__/todo.cpython-313.pyc +0 -0
  65. package/backend/src/flowent/models/agent.py +33 -0
  66. package/backend/src/flowent/models/base.py +24 -0
  67. package/backend/src/flowent/models/blueprint.py +176 -0
  68. package/backend/src/flowent/models/content.py +164 -0
  69. package/backend/src/flowent/models/delta.py +44 -0
  70. package/backend/src/flowent/models/event.py +51 -0
  71. package/backend/src/flowent/models/graph.py +437 -0
  72. package/backend/src/flowent/models/history.py +214 -0
  73. package/backend/src/flowent/models/llm.py +61 -0
  74. package/backend/src/flowent/models/message.py +27 -0
  75. package/backend/src/flowent/models/tab.py +48 -0
  76. package/backend/src/flowent/models/todo.py +10 -0
  77. package/backend/src/flowent/network.py +146 -0
  78. package/backend/src/flowent/prompts/__init__.py +67 -0
  79. package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  80. package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
  81. package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
  82. package/backend/src/flowent/prompts/common.py +250 -0
  83. package/backend/src/flowent/prompts/steward.py +64 -0
  84. package/backend/src/flowent/providers/__init__.py +23 -0
  85. package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  86. package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
  87. package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
  88. package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
  89. package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
  90. package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
  91. package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
  92. package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
  93. package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
  94. package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
  95. package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
  96. package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
  97. package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
  98. package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
  99. package/backend/src/flowent/providers/anthropic.py +468 -0
  100. package/backend/src/flowent/providers/base_url.py +60 -0
  101. package/backend/src/flowent/providers/configuration.py +182 -0
  102. package/backend/src/flowent/providers/content.py +122 -0
  103. package/backend/src/flowent/providers/errors.py +223 -0
  104. package/backend/src/flowent/providers/gateway.py +169 -0
  105. package/backend/src/flowent/providers/gemini.py +447 -0
  106. package/backend/src/flowent/providers/headers.py +20 -0
  107. package/backend/src/flowent/providers/management.py +96 -0
  108. package/backend/src/flowent/providers/ollama.py +293 -0
  109. package/backend/src/flowent/providers/openai.py +422 -0
  110. package/backend/src/flowent/providers/openai_responses.py +655 -0
  111. package/backend/src/flowent/providers/registry.py +144 -0
  112. package/backend/src/flowent/providers/sse.py +31 -0
  113. package/backend/src/flowent/providers/thinking.py +79 -0
  114. package/backend/src/flowent/registry.py +73 -0
  115. package/backend/src/flowent/role_management.py +255 -0
  116. package/backend/src/flowent/routes/__init__.py +30 -0
  117. package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
  118. package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
  119. package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
  120. package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
  121. package/backend/src/flowent/routes/__pycache__/mcp.cpython-313.pyc +0 -0
  122. package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
  123. package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
  124. package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
  125. package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
  126. package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
  127. package/backend/src/flowent/routes/__pycache__/settings.cpython-313.pyc +0 -0
  128. package/backend/src/flowent/routes/__pycache__/stats.cpython-313.pyc +0 -0
  129. package/backend/src/flowent/routes/__pycache__/tabs.cpython-313.pyc +0 -0
  130. package/backend/src/flowent/routes/__pycache__/ws.cpython-313.pyc +0 -0
  131. package/backend/src/flowent/routes/access.py +48 -0
  132. package/backend/src/flowent/routes/assistant.py +155 -0
  133. package/backend/src/flowent/routes/image_assets.py +33 -0
  134. package/backend/src/flowent/routes/mcp.py +125 -0
  135. package/backend/src/flowent/routes/meta.py +28 -0
  136. package/backend/src/flowent/routes/nodes.py +365 -0
  137. package/backend/src/flowent/routes/prompts.py +46 -0
  138. package/backend/src/flowent/routes/providers_route.py +364 -0
  139. package/backend/src/flowent/routes/roles.py +207 -0
  140. package/backend/src/flowent/routes/settings.py +324 -0
  141. package/backend/src/flowent/routes/stats.py +229 -0
  142. package/backend/src/flowent/routes/tabs.py +292 -0
  143. package/backend/src/flowent/routes/ws.py +33 -0
  144. package/backend/src/flowent/runtime.py +188 -0
  145. package/backend/src/flowent/sandbox.py +45 -0
  146. package/backend/src/flowent/security.py +42 -0
  147. package/backend/src/flowent/settings.py +2467 -0
  148. package/backend/src/flowent/settings_management.py +286 -0
  149. package/backend/src/flowent/state_db.py +120 -0
  150. package/backend/src/flowent/static/assets/AssistantPage-B3Xc08AS.js +1 -0
  151. package/backend/src/flowent/static/assets/ChannelsPage-ByLd28xk.js +1 -0
  152. package/backend/src/flowent/static/assets/HomePage-C0hAx9_l.js +3 -0
  153. package/backend/src/flowent/static/assets/McpPage-DkrYLvBv.js +7 -0
  154. package/backend/src/flowent/static/assets/PageScaffold-D4jO9ooX.js +1 -0
  155. package/backend/src/flowent/static/assets/PromptsPage-DWA7rRJd.js +1 -0
  156. package/backend/src/flowent/static/assets/ProvidersPage-PUWT8seJ.js +3 -0
  157. package/backend/src/flowent/static/assets/RolesPage-CqcclGRw.js +1 -0
  158. package/backend/src/flowent/static/assets/SettingsPage-8tS2cJgX.js +3 -0
  159. package/backend/src/flowent/static/assets/StatsPage-BX9khYzu.js +1 -0
  160. package/backend/src/flowent/static/assets/ToolsPage-9Tl9FdeD.js +1 -0
  161. package/backend/src/flowent/static/assets/WorkspaceCommandDialog-CCXxjDL8.js +1 -0
  162. package/backend/src/flowent/static/assets/WorkspacePanels-aMdJ7ZH7.js +1 -0
  163. package/backend/src/flowent/static/assets/alert-dialog-kFYVQ7oX.js +1 -0
  164. package/backend/src/flowent/static/assets/badge-74-3jsCg.js +1 -0
  165. package/backend/src/flowent/static/assets/constants-XUzFf6i1.js +1 -0
  166. package/backend/src/flowent/static/assets/datetime-m6_O_Ci9.js +1 -0
  167. package/backend/src/flowent/static/assets/dialog-BeGSweF6.js +1 -0
  168. package/backend/src/flowent/static/assets/elk-worker.min-C9JGDOE-.js +6312 -0
  169. package/backend/src/flowent/static/assets/graph-vendor-CHpVij2M.css +1 -0
  170. package/backend/src/flowent/static/assets/graph-vendor-DRq_-6fV.js +7 -0
  171. package/backend/src/flowent/static/assets/index-BHC1Vhy8.css +1 -0
  172. package/backend/src/flowent/static/assets/index-CL1ALZ3r.js +10 -0
  173. package/backend/src/flowent/static/assets/layout.worker-jMHqAFbP.js +24 -0
  174. package/backend/src/flowent/static/assets/markdown-vendor-DVdy_w12.js +29 -0
  175. package/backend/src/flowent/static/assets/modelParams-CaHd0903.js +1 -0
  176. package/backend/src/flowent/static/assets/react-vendor-mEs_JJxa.js +9 -0
  177. package/backend/src/flowent/static/assets/roles-2OLDeTc5.js +1 -0
  178. package/backend/src/flowent/static/assets/rolldown-runtime-BYbx6iT9.js +1 -0
  179. package/backend/src/flowent/static/assets/select-DL_LPeDj.js +1 -0
  180. package/backend/src/flowent/static/assets/shared-CMxbpLeQ.js +1 -0
  181. package/backend/src/flowent/static/assets/triState-DEr3NkXV.js +1 -0
  182. package/backend/src/flowent/static/assets/ui-vendor-Dg9NNnWX.js +51 -0
  183. package/backend/src/flowent/static/index.html +36 -0
  184. package/backend/src/flowent/stats_service.py +218 -0
  185. package/backend/src/flowent/tools/__init__.py +201 -0
  186. package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  187. package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
  188. package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
  189. package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
  190. package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
  191. package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
  192. package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
  193. package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
  194. package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
  195. package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
  196. package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
  197. package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
  198. package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
  199. package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
  200. package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
  201. package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
  202. package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
  203. package/backend/src/flowent/tools/__pycache__/mcp.cpython-313.pyc +0 -0
  204. package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
  205. package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
  206. package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
  207. package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
  208. package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
  209. package/backend/src/flowent/tools/connect.py +156 -0
  210. package/backend/src/flowent/tools/contacts.py +22 -0
  211. package/backend/src/flowent/tools/create_agent.py +270 -0
  212. package/backend/src/flowent/tools/create_tab.py +59 -0
  213. package/backend/src/flowent/tools/delete_tab.py +39 -0
  214. package/backend/src/flowent/tools/edit.py +142 -0
  215. package/backend/src/flowent/tools/exec.py +117 -0
  216. package/backend/src/flowent/tools/fetch.py +85 -0
  217. package/backend/src/flowent/tools/idle.py +27 -0
  218. package/backend/src/flowent/tools/list_roles.py +50 -0
  219. package/backend/src/flowent/tools/list_tabs.py +96 -0
  220. package/backend/src/flowent/tools/list_tools.py +24 -0
  221. package/backend/src/flowent/tools/manage_prompts.py +102 -0
  222. package/backend/src/flowent/tools/manage_providers.py +220 -0
  223. package/backend/src/flowent/tools/manage_roles.py +275 -0
  224. package/backend/src/flowent/tools/manage_settings.py +346 -0
  225. package/backend/src/flowent/tools/mcp.py +199 -0
  226. package/backend/src/flowent/tools/read.py +152 -0
  227. package/backend/src/flowent/tools/send.py +50 -0
  228. package/backend/src/flowent/tools/set_permissions.py +84 -0
  229. package/backend/src/flowent/tools/sleep.py +41 -0
  230. package/backend/src/flowent/tools/todo.py +51 -0
  231. package/backend/src/flowent/workspace_store.py +479 -0
  232. package/backend/tests/__init__.py +0 -0
  233. package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  234. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  235. package/backend/tests/conftest.py +6 -0
  236. package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  237. package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
  238. package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
  239. package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
  240. package/backend/tests/integration/api/__pycache__/test_mcp_api.cpython-313-pytest-9.0.3.pyc +0 -0
  241. package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
  242. package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
  243. package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
  244. package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
  245. package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
  246. package/backend/tests/integration/api/conftest.py +29 -0
  247. package/backend/tests/integration/api/test_access_api.py +182 -0
  248. package/backend/tests/integration/api/test_assistant_api.py +354 -0
  249. package/backend/tests/integration/api/test_frontend_mounting.py +61 -0
  250. package/backend/tests/integration/api/test_mcp_api.py +116 -0
  251. package/backend/tests/integration/api/test_meta_api.py +33 -0
  252. package/backend/tests/integration/api/test_nodes_api.py +486 -0
  253. package/backend/tests/integration/api/test_prompts_api.py +47 -0
  254. package/backend/tests/integration/api/test_roles_api.py +227 -0
  255. package/backend/tests/integration/api/test_tabs_api.py +501 -0
  256. package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
  257. package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  258. package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  259. package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
  260. package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
  261. package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
  262. package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
  263. package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  264. package/backend/tests/unit/agent/test_agent_public_api.py +746 -0
  265. package/backend/tests/unit/agent/test_agent_runtime.py +2726 -0
  266. package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
  267. package/backend/tests/unit/channels/test_telegram_channel.py +552 -0
  268. package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  269. package/backend/tests/unit/logging/test_logging.py +132 -0
  270. package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
  271. package/backend/tests/unit/prompts/test_prompts.py +569 -0
  272. package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  273. package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
  274. package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
  275. package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  276. package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
  277. package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
  278. package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
  279. package/backend/tests/unit/providers/test_anthropic_provider.py +185 -0
  280. package/backend/tests/unit/providers/test_errors.py +68 -0
  281. package/backend/tests/unit/providers/test_extract_delta_parts.py +22 -0
  282. package/backend/tests/unit/providers/test_openai_provider.py +139 -0
  283. package/backend/tests/unit/providers/test_openai_responses.py +402 -0
  284. package/backend/tests/unit/providers/test_provider_gateway.py +359 -0
  285. package/backend/tests/unit/providers/test_think_tag_parser.py +36 -0
  286. package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  287. package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
  288. package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  289. package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  290. package/backend/tests/unit/routes/__pycache__/test_stats_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  291. package/backend/tests/unit/routes/test_prompts_routes.py +104 -0
  292. package/backend/tests/unit/routes/test_providers_route.py +368 -0
  293. package/backend/tests/unit/routes/test_roles_routes.py +426 -0
  294. package/backend/tests/unit/routes/test_settings_routes.py +1138 -0
  295. package/backend/tests/unit/routes/test_stats_routes.py +149 -0
  296. package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  297. package/backend/tests/unit/runtime/test_bootstrap_runtime.py +1012 -0
  298. package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  299. package/backend/tests/unit/sandbox/test_sandbox_tools.py +78 -0
  300. package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
  301. package/backend/tests/unit/security/test_security.py +110 -0
  302. package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
  303. package/backend/tests/unit/settings/test_settings_roles.py +711 -0
  304. package/backend/tests/unit/test_access.py +45 -0
  305. package/backend/tests/unit/test_cli.py +124 -0
  306. package/backend/tests/unit/test_graph_runtime.py +72 -0
  307. package/backend/tests/unit/test_network.py +51 -0
  308. package/backend/tests/unit/test_state_sqlite_storage.py +93 -0
  309. package/backend/tests/unit/test_workspace_store.py +231 -0
  310. package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  311. package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  312. package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  313. package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  314. package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  315. package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  316. package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  317. package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  318. package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  319. package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  320. package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  321. package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  322. package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  323. package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
  324. package/backend/tests/unit/tools/test_connect_tool.py +229 -0
  325. package/backend/tests/unit/tools/test_create_agent_tool.py +524 -0
  326. package/backend/tests/unit/tools/test_delete_tab_tool.py +83 -0
  327. package/backend/tests/unit/tools/test_edit_tool.py +115 -0
  328. package/backend/tests/unit/tools/test_exec_tool.py +81 -0
  329. package/backend/tests/unit/tools/test_fetch_tool.py +65 -0
  330. package/backend/tests/unit/tools/test_manage_prompts_tool.py +117 -0
  331. package/backend/tests/unit/tools/test_manage_providers_tool.py +458 -0
  332. package/backend/tests/unit/tools/test_manage_roles_tool.py +411 -0
  333. package/backend/tests/unit/tools/test_manage_settings_tool.py +608 -0
  334. package/backend/tests/unit/tools/test_read_tool.py +33 -0
  335. package/backend/tests/unit/tools/test_set_permissions_tool.py +391 -0
  336. package/backend/tests/unit/tools/test_todo_tool.py +37 -0
  337. package/backend/tests/unit/tools/test_tool_registry.py +91 -0
  338. package/backend/uv.lock +1144 -0
  339. package/bin/flowent.mjs +62 -35
  340. package/dist/frontend/assets/AssistantPage-B3Xc08AS.js +1 -0
  341. package/dist/frontend/assets/ChannelsPage-ByLd28xk.js +1 -0
  342. package/dist/frontend/assets/HomePage-C0hAx9_l.js +3 -0
  343. package/dist/frontend/assets/McpPage-DkrYLvBv.js +7 -0
  344. package/dist/frontend/assets/PageScaffold-D4jO9ooX.js +1 -0
  345. package/dist/frontend/assets/PromptsPage-DWA7rRJd.js +1 -0
  346. package/dist/frontend/assets/ProvidersPage-PUWT8seJ.js +3 -0
  347. package/dist/frontend/assets/RolesPage-CqcclGRw.js +1 -0
  348. package/dist/frontend/assets/SettingsPage-8tS2cJgX.js +3 -0
  349. package/dist/frontend/assets/StatsPage-BX9khYzu.js +1 -0
  350. package/dist/frontend/assets/ToolsPage-9Tl9FdeD.js +1 -0
  351. package/dist/frontend/assets/WorkspaceCommandDialog-CCXxjDL8.js +1 -0
  352. package/dist/frontend/assets/WorkspacePanels-aMdJ7ZH7.js +1 -0
  353. package/dist/frontend/assets/alert-dialog-kFYVQ7oX.js +1 -0
  354. package/dist/frontend/assets/badge-74-3jsCg.js +1 -0
  355. package/dist/frontend/assets/constants-XUzFf6i1.js +1 -0
  356. package/dist/frontend/assets/datetime-m6_O_Ci9.js +1 -0
  357. package/dist/frontend/assets/dialog-BeGSweF6.js +1 -0
  358. package/dist/frontend/assets/elk-worker.min-C9JGDOE-.js +6312 -0
  359. package/dist/frontend/assets/graph-vendor-CHpVij2M.css +1 -0
  360. package/dist/frontend/assets/graph-vendor-DRq_-6fV.js +7 -0
  361. package/dist/frontend/assets/index-BHC1Vhy8.css +1 -0
  362. package/dist/frontend/assets/index-CL1ALZ3r.js +10 -0
  363. package/dist/frontend/assets/layout.worker-jMHqAFbP.js +24 -0
  364. package/dist/frontend/assets/markdown-vendor-DVdy_w12.js +29 -0
  365. package/dist/frontend/assets/modelParams-CaHd0903.js +1 -0
  366. package/dist/frontend/assets/react-vendor-mEs_JJxa.js +9 -0
  367. package/dist/frontend/assets/roles-2OLDeTc5.js +1 -0
  368. package/dist/frontend/assets/rolldown-runtime-BYbx6iT9.js +1 -0
  369. package/dist/frontend/assets/select-DL_LPeDj.js +1 -0
  370. package/dist/frontend/assets/shared-CMxbpLeQ.js +1 -0
  371. package/dist/frontend/assets/triState-DEr3NkXV.js +1 -0
  372. package/dist/frontend/assets/ui-vendor-Dg9NNnWX.js +51 -0
  373. package/dist/frontend/index.html +36 -0
  374. package/package.json +28 -41
  375. package/dist/.next/BUILD_ID +0 -1
  376. package/dist/.next/app-path-routes-manifest.json +0 -6
  377. package/dist/.next/build-manifest.json +0 -20
  378. package/dist/.next/package.json +0 -1
  379. package/dist/.next/prerender-manifest.json +0 -114
  380. package/dist/.next/required-server-files.json +0 -333
  381. package/dist/.next/routes-manifest.json +0 -69
  382. package/dist/.next/server/app/_global-error/page/app-paths-manifest.json +0 -3
  383. package/dist/.next/server/app/_global-error/page/build-manifest.json +0 -16
  384. package/dist/.next/server/app/_global-error/page/next-font-manifest.json +0 -6
  385. package/dist/.next/server/app/_global-error/page/react-loadable-manifest.json +0 -1
  386. package/dist/.next/server/app/_global-error/page/server-reference-manifest.json +0 -4
  387. package/dist/.next/server/app/_global-error/page.js +0 -9
  388. package/dist/.next/server/app/_global-error/page.js.map +0 -5
  389. package/dist/.next/server/app/_global-error/page.js.nft.json +0 -1
  390. package/dist/.next/server/app/_global-error/page_client-reference-manifest.js +0 -3
  391. package/dist/.next/server/app/_global-error.html +0 -1
  392. package/dist/.next/server/app/_global-error.meta +0 -15
  393. package/dist/.next/server/app/_global-error.rsc +0 -14
  394. package/dist/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +0 -5
  395. package/dist/.next/server/app/_global-error.segments/_full.segment.rsc +0 -14
  396. package/dist/.next/server/app/_global-error.segments/_head.segment.rsc +0 -5
  397. package/dist/.next/server/app/_global-error.segments/_index.segment.rsc +0 -5
  398. package/dist/.next/server/app/_global-error.segments/_tree.segment.rsc +0 -1
  399. package/dist/.next/server/app/_not-found/page/app-paths-manifest.json +0 -3
  400. package/dist/.next/server/app/_not-found/page/build-manifest.json +0 -16
  401. package/dist/.next/server/app/_not-found/page/next-font-manifest.json +0 -10
  402. package/dist/.next/server/app/_not-found/page/react-loadable-manifest.json +0 -1
  403. package/dist/.next/server/app/_not-found/page/server-reference-manifest.json +0 -4
  404. package/dist/.next/server/app/_not-found/page.js +0 -13
  405. package/dist/.next/server/app/_not-found/page.js.map +0 -5
  406. package/dist/.next/server/app/_not-found/page.js.nft.json +0 -1
  407. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +0 -3
  408. package/dist/.next/server/app/_not-found.html +0 -1
  409. package/dist/.next/server/app/_not-found.meta +0 -16
  410. package/dist/.next/server/app/_not-found.rsc +0 -16
  411. package/dist/.next/server/app/_not-found.segments/_full.segment.rsc +0 -16
  412. package/dist/.next/server/app/_not-found.segments/_head.segment.rsc +0 -6
  413. package/dist/.next/server/app/_not-found.segments/_index.segment.rsc +0 -5
  414. package/dist/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +0 -5
  415. package/dist/.next/server/app/_not-found.segments/_not-found.segment.rsc +0 -5
  416. package/dist/.next/server/app/_not-found.segments/_tree.segment.rsc +0 -2
  417. package/dist/.next/server/app/icon.svg/route/app-paths-manifest.json +0 -3
  418. package/dist/.next/server/app/icon.svg/route/build-manifest.json +0 -9
  419. package/dist/.next/server/app/icon.svg/route.js +0 -6
  420. package/dist/.next/server/app/icon.svg/route.js.map +0 -5
  421. package/dist/.next/server/app/icon.svg/route.js.nft.json +0 -1
  422. package/dist/.next/server/app/icon.svg.meta +0 -1
  423. package/dist/.next/server/app/index.html +0 -1
  424. package/dist/.next/server/app/index.meta +0 -14
  425. package/dist/.next/server/app/index.rsc +0 -15
  426. package/dist/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -5
  427. package/dist/.next/server/app/index.segments/_full.segment.rsc +0 -15
  428. package/dist/.next/server/app/index.segments/_head.segment.rsc +0 -6
  429. package/dist/.next/server/app/index.segments/_index.segment.rsc +0 -5
  430. package/dist/.next/server/app/index.segments/_tree.segment.rsc +0 -3
  431. package/dist/.next/server/app/page/app-paths-manifest.json +0 -3
  432. package/dist/.next/server/app/page/build-manifest.json +0 -16
  433. package/dist/.next/server/app/page/next-font-manifest.json +0 -10
  434. package/dist/.next/server/app/page/react-loadable-manifest.json +0 -1
  435. package/dist/.next/server/app/page/server-reference-manifest.json +0 -4
  436. package/dist/.next/server/app/page.js +0 -14
  437. package/dist/.next/server/app/page.js.map +0 -5
  438. package/dist/.next/server/app/page.js.nft.json +0 -1
  439. package/dist/.next/server/app/page_client-reference-manifest.js +0 -3
  440. package/dist/.next/server/app-paths-manifest.json +0 -6
  441. package/dist/.next/server/chunks/[externals]_next_dist_0arv.vj._.js +0 -3
  442. package/dist/.next/server/chunks/[root-of-the-server]__0vcj1q1._.js +0 -13
  443. package/dist/.next/server/chunks/[turbopack]_runtime.js +0 -903
  444. package/dist/.next/server/chunks/_next-internal_server_app_icon_svg_route_actions_0-0ehc~.js +0 -3
  445. package/dist/.next/server/chunks/ssr/05w9_next_dist_0ihu0u9._.js +0 -6
  446. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_12u3mib._.js +0 -3
  447. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_builtin_forbidden_04fbe_..js +0 -3
  448. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_builtin_global-error_0brpl_..js +0 -3
  449. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_builtin_unauthorized_0~2g66g.js +0 -3
  450. package/dist/.next/server/chunks/ssr/05w9_next_dist_esm_build_templates_app-page_0~cyr1_.js +0 -4
  451. package/dist/.next/server/chunks/ssr/05w9_next_dist_esm_build_templates_app-page_1105emf.js +0 -4
  452. package/dist/.next/server/chunks/ssr/05w9_next_dist_esm_build_templates_app-page_11uhyqv.js +0 -4
  453. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0.t9_75._.js +0 -33
  454. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0c0ud_z._.js +0 -3
  455. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0f9_8d4._.js +0 -3
  456. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0l5ko41._.js +0 -19
  457. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0mn6z7i._.js +0 -3
  458. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0npxxst._.js +0 -33
  459. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0qjhaca._.js +0 -3
  460. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0rwgw3s._.js +0 -3
  461. package/dist/.next/server/chunks/ssr/[turbopack]_runtime.js +0 -903
  462. package/dist/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0k77kol.js +0 -3
  463. package/dist/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0eq97pa.js +0 -3
  464. package/dist/.next/server/chunks/ssr/_next-internal_server_app_page_actions_09-gtaw.js +0 -3
  465. package/dist/.next/server/chunks/ssr/node_modules__pnpm_056~6.6._.js +0 -3
  466. package/dist/.next/server/chunks/ssr/node_modules__pnpm_0~j0k.e._.js +0 -33
  467. package/dist/.next/server/functions-config-manifest.json +0 -4
  468. package/dist/.next/server/middleware-build-manifest.js +0 -20
  469. package/dist/.next/server/middleware-manifest.json +0 -6
  470. package/dist/.next/server/next-font-manifest.js +0 -1
  471. package/dist/.next/server/next-font-manifest.json +0 -13
  472. package/dist/.next/server/pages/404.html +0 -1
  473. package/dist/.next/server/pages/500.html +0 -1
  474. package/dist/.next/server/pages-manifest.json +0 -4
  475. package/dist/.next/server/prefetch-hints.json +0 -1
  476. package/dist/.next/server/server-reference-manifest.js +0 -1
  477. package/dist/.next/server/server-reference-manifest.json +0 -5
  478. package/dist/.next/static/7FFlzRe2eS-D0Lw5oEpmC/_buildManifest.js +0 -11
  479. package/dist/.next/static/7FFlzRe2eS-D0Lw5oEpmC/_clientMiddlewareManifest.js +0 -1
  480. package/dist/.next/static/7FFlzRe2eS-D0Lw5oEpmC/_ssgManifest.js +0 -1
  481. package/dist/.next/static/chunks/01qk2~bgf76vu.js +0 -1
  482. package/dist/.next/static/chunks/03~yq9q893hmn.js +0 -1
  483. package/dist/.next/static/chunks/080queev.r2uy.js +0 -31
  484. package/dist/.next/static/chunks/0v3lyuj75aq50.js +0 -1
  485. package/dist/.next/static/chunks/10b~xdx5c-i7s.js +0 -5
  486. package/dist/.next/static/chunks/15~9l5n.~r-.4.css +0 -2
  487. package/dist/.next/static/chunks/turbopack-0m-970~qvs7sc.js +0 -1
  488. package/dist/.next/static/media/7178b3e590c64307-s.11.cyxs5p-0z~.woff2 +0 -0
  489. package/dist/.next/static/media/8a480f0b521d4e75-s.06d3mdzz5bre_.woff2 +0 -0
  490. package/dist/.next/static/media/caa3a2e1cccd8315-s.p.16t1db8_9y2o~.woff2 +0 -0
  491. package/dist/package.json +0 -87
  492. package/dist/server.js +0 -38
  493. /package/{dist/.next/server/app/icon.svg.body → backend/src/flowent/static/favicon.svg} +0 -0
  494. /package/dist/{.next/static/media/icon.0.r~afrtrocz9.svg → frontend/favicon.svg} +0 -0
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass, field
4
+ from typing import Any
5
+
6
+
7
+ @dataclass
8
+ class ModelCapabilities:
9
+ input_image: bool = False
10
+ output_image: bool = False
11
+
12
+
13
+ @dataclass
14
+ class ModelInfo:
15
+ id: str
16
+ capabilities: ModelCapabilities = field(default_factory=ModelCapabilities)
17
+ context_window_tokens: int | None = None
18
+
19
+
20
+ @dataclass
21
+ class LLMUsage:
22
+ total_tokens: int
23
+ input_tokens: int | None = None
24
+ output_tokens: int | None = None
25
+ cached_input_tokens: int | None = None
26
+ cache_read_tokens: int | None = None
27
+ cache_write_tokens: int | None = None
28
+ details: dict[str, int] = field(default_factory=dict)
29
+
30
+
31
+ @dataclass
32
+ class ToolCallResult:
33
+ id: str
34
+ name: str
35
+ arguments: dict[str, Any]
36
+
37
+
38
+ @dataclass
39
+ class LLMOutputTextPart:
40
+ text: str
41
+
42
+
43
+ @dataclass
44
+ class LLMOutputImagePart:
45
+ data: bytes
46
+ mime_type: str
47
+ width: int | None = None
48
+ height: int | None = None
49
+
50
+
51
+ LLMOutputPart = LLMOutputTextPart | LLMOutputImagePart
52
+
53
+
54
+ @dataclass
55
+ class LLMResponse:
56
+ content: str | None = None
57
+ parts: list[LLMOutputPart] | None = None
58
+ tool_calls: list[ToolCallResult] | None = None
59
+ thinking: str | None = None
60
+ usage: LLMUsage | None = None
61
+ raw_usage: dict[str, Any] | None = None
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from dataclasses import dataclass, field
5
+
6
+ from flowent.models.content import (
7
+ ContentPart,
8
+ content_parts_to_text,
9
+ deserialize_content_parts,
10
+ )
11
+
12
+
13
+ @dataclass
14
+ class Message:
15
+ from_id: str
16
+ to_id: str
17
+ parts: list[ContentPart] = field(default_factory=list)
18
+ content: str = ""
19
+ message_id: str | None = None
20
+ history_recorded: bool = False
21
+ timestamp: float = field(default_factory=time.time)
22
+
23
+ def __post_init__(self) -> None:
24
+ if self.parts and not self.content:
25
+ self.content = content_parts_to_text(self.parts)
26
+ elif self.content and not self.parts:
27
+ self.parts = deserialize_content_parts(None, fallback_text=self.content)
@@ -0,0 +1,48 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from dataclasses import dataclass, field
5
+
6
+ from flowent.models.graph import WorkflowDefinition
7
+
8
+
9
+ @dataclass
10
+ class Tab:
11
+ id: str
12
+ title: str
13
+ leader_id: str | None = None
14
+ definition: WorkflowDefinition = field(default_factory=WorkflowDefinition)
15
+ created_at: float = field(default_factory=time.time)
16
+ updated_at: float = field(default_factory=time.time)
17
+
18
+ def serialize(self) -> dict[str, object]:
19
+ return {
20
+ "id": self.id,
21
+ "title": self.title,
22
+ "leader_id": self.leader_id,
23
+ "definition": self.definition.serialize(),
24
+ "created_at": self.created_at,
25
+ "updated_at": self.updated_at,
26
+ }
27
+
28
+ @classmethod
29
+ def from_mapping(cls, data: dict[str, object]) -> Tab:
30
+ created_at = data.get("created_at")
31
+ updated_at = data.get("updated_at")
32
+ raw_definition = data.get("definition")
33
+ return cls(
34
+ id=str(data.get("id", "")),
35
+ title=str(data.get("title", "")),
36
+ leader_id=str(data["leader_id"])
37
+ if isinstance(data.get("leader_id"), str)
38
+ else None,
39
+ definition=WorkflowDefinition.from_mapping(
40
+ raw_definition if isinstance(raw_definition, dict) else None
41
+ ),
42
+ created_at=created_at
43
+ if isinstance(created_at, (int, float))
44
+ else time.time(),
45
+ updated_at=updated_at
46
+ if isinstance(updated_at, (int, float))
47
+ else time.time(),
48
+ )
@@ -0,0 +1,10 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+
5
+ from flowent.models.base import Serializable
6
+
7
+
8
+ @dataclass
9
+ class TodoItem(Serializable):
10
+ text: str
@@ -0,0 +1,146 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterator
4
+ from typing import Any, Literal
5
+
6
+ from curl_cffi.requests import AsyncSession, Session
7
+ from curl_cffi.requests.exceptions import RequestException
8
+
9
+ DEFAULT_BROWSER_IMPERSONATE: Literal["chrome"] = "chrome"
10
+
11
+
12
+ def create_http_session(
13
+ *,
14
+ timeout: float,
15
+ impersonate_browser: bool = False,
16
+ ) -> Session:
17
+ kwargs: dict[str, Any] = {"timeout": timeout}
18
+ if impersonate_browser:
19
+ kwargs["impersonate"] = DEFAULT_BROWSER_IMPERSONATE
20
+ return Session(**kwargs)
21
+
22
+
23
+ def create_async_http_session(
24
+ *,
25
+ timeout: float,
26
+ impersonate_browser: bool = False,
27
+ ) -> AsyncSession:
28
+ kwargs: dict[str, Any] = {"timeout": timeout}
29
+ if impersonate_browser:
30
+ kwargs["impersonate"] = DEFAULT_BROWSER_IMPERSONATE
31
+ return AsyncSession(**kwargs)
32
+
33
+
34
+ def is_success_status(status_code: int) -> bool:
35
+ return 200 <= status_code < 300
36
+
37
+
38
+ def iter_response_lines(response: Any) -> Iterator[str]:
39
+ for line in response.iter_lines():
40
+ normalized = _decode_to_text(line)
41
+ if normalized:
42
+ yield normalized
43
+
44
+
45
+ def iter_response_text(response: Any) -> Iterator[str]:
46
+ iter_text = getattr(response, "iter_text", None)
47
+ if callable(iter_text):
48
+ for chunk in iter_text():
49
+ normalized = _decode_to_text(chunk)
50
+ if normalized:
51
+ yield normalized
52
+ return
53
+
54
+ for chunk in response.iter_content():
55
+ normalized = _decode_to_text(chunk)
56
+ if normalized:
57
+ yield normalized
58
+
59
+
60
+ def read_response_text(response: Any) -> str:
61
+ text = getattr(response, "text", None)
62
+ if isinstance(text, str) and text:
63
+ return text
64
+
65
+ content = getattr(response, "content", None)
66
+ if isinstance(content, str) and content:
67
+ return content
68
+ if isinstance(content, (bytes, bytearray)) and content:
69
+ return bytes(content).decode("utf-8", errors="replace")
70
+
71
+ iter_text = getattr(response, "iter_text", None)
72
+ if callable(iter_text):
73
+ chunks = [_decode_to_text(chunk) for chunk in iter_text()]
74
+ if chunks:
75
+ return "".join(chunks)
76
+
77
+ iter_content = getattr(response, "iter_content", None)
78
+ if callable(iter_content):
79
+ chunks = [_decode_to_text(chunk) for chunk in iter_content()]
80
+ if chunks:
81
+ return "".join(chunks)
82
+
83
+ read = getattr(response, "read", None)
84
+ if callable(read):
85
+ payload = read()
86
+ if isinstance(payload, str):
87
+ return payload
88
+ if isinstance(payload, (bytes, bytearray)):
89
+ return bytes(payload).decode("utf-8", errors="replace")
90
+
91
+ return ""
92
+
93
+
94
+ def get_response_header(response: Any, header_name: str) -> str | None:
95
+ headers = getattr(response, "headers", None)
96
+ if headers is None:
97
+ return None
98
+ getter = getattr(headers, "get", None)
99
+ if callable(getter):
100
+ value = getter(header_name)
101
+ if isinstance(value, str):
102
+ return value
103
+ if isinstance(headers, dict):
104
+ value = headers.get(header_name) or headers.get(header_name.lower())
105
+ if isinstance(value, str):
106
+ return value
107
+ return None
108
+
109
+
110
+ def response_looks_like_html(response: Any) -> bool:
111
+ content_type = get_response_header(response, "content-type")
112
+ if not isinstance(content_type, str):
113
+ return False
114
+ normalized = content_type.lower()
115
+ return "text/html" in normalized or "application/xhtml+xml" in normalized
116
+
117
+
118
+ def truncate_text(text: str, limit: int = 500) -> str:
119
+ if len(text) <= limit:
120
+ return text
121
+ return text[:limit]
122
+
123
+
124
+ def _decode_to_text(value: Any) -> str:
125
+ if isinstance(value, str):
126
+ return value
127
+ if isinstance(value, (bytes, bytearray)):
128
+ return bytes(value).decode("utf-8", errors="replace")
129
+ return str(value)
130
+
131
+
132
+ __all__ = [
133
+ "DEFAULT_BROWSER_IMPERSONATE",
134
+ "AsyncSession",
135
+ "RequestException",
136
+ "Session",
137
+ "create_async_http_session",
138
+ "create_http_session",
139
+ "get_response_header",
140
+ "is_success_status",
141
+ "iter_response_lines",
142
+ "iter_response_text",
143
+ "read_response_text",
144
+ "response_looks_like_html",
145
+ "truncate_text",
146
+ ]
@@ -0,0 +1,67 @@
1
+ from __future__ import annotations
2
+
3
+ from flowent.models import NodeConfig, NodeType
4
+ from flowent.prompts.common import DEFAULT_AGENT_ROLE_PROMPT, compose_system_prompt
5
+ from flowent.prompts.steward import STEWARD_ROLE_SYSTEM_PROMPT
6
+ from flowent.tools import MINIMUM_TOOLS
7
+
8
+
9
+ def _get_assistant_role_prompt(*, settings, role_name: str) -> str:
10
+ from flowent.settings import STEWARD_ROLE_NAME, find_role
11
+
12
+ normalized_role_name = role_name.strip()
13
+ role = find_role(settings, normalized_role_name)
14
+ if role is None or normalized_role_name == STEWARD_ROLE_NAME:
15
+ return STEWARD_ROLE_SYSTEM_PROMPT
16
+
17
+ overlay_prompt = role.system_prompt.strip()
18
+ if not overlay_prompt:
19
+ return STEWARD_ROLE_SYSTEM_PROMPT
20
+
21
+ return "\n\n".join(
22
+ [
23
+ STEWARD_ROLE_SYSTEM_PROMPT.strip(),
24
+ f"""\
25
+ ## Selected Role Overlay
26
+
27
+ The Assistant is currently configured to use the role "{role.name}" as an additional behavior template.
28
+ Use the selected role to adjust tone, specialization, model tendency, and any extra tool usage that fits the Assistant surface.
29
+ Do not follow any selected-role instruction that would redefine you as a Worker, Designer, Leader, or regular workflow node, or that would drop your Human-facing intake and workspace-boundary responsibilities.
30
+
31
+ ### Selected Role Prompt
32
+
33
+ {overlay_prompt}""".strip(),
34
+ ]
35
+ )
36
+
37
+
38
+ def get_system_prompt(config: NodeConfig) -> str:
39
+ from flowent.settings import (
40
+ STEWARD_ROLE_NAME,
41
+ get_settings,
42
+ normalize_tool_names,
43
+ )
44
+
45
+ settings = get_settings()
46
+ tools = normalize_tool_names([*config.tools, *MINIMUM_TOOLS])
47
+
48
+ if config.node_type == NodeType.ASSISTANT:
49
+ role_name = (
50
+ config.role_name or settings.assistant.role_name or STEWARD_ROLE_NAME
51
+ )
52
+ prompt = _get_assistant_role_prompt(settings=settings, role_name=role_name)
53
+ else:
54
+ prompt = DEFAULT_AGENT_ROLE_PROMPT
55
+ if config.role_name:
56
+ from flowent.settings import find_role
57
+
58
+ role = find_role(settings, config.role_name)
59
+ if role:
60
+ prompt = role.system_prompt
61
+
62
+ return compose_system_prompt(
63
+ prompt,
64
+ custom_prompt=settings.custom_prompt,
65
+ is_assistant=config.node_type == NodeType.ASSISTANT,
66
+ tools=tools,
67
+ )
@@ -0,0 +1,250 @@
1
+ IDLE_TOOL_GUIDANCE = """\
2
+ ## Idle Usage Rules
3
+
4
+ - `idle` means you are not taking another immediate action right now.
5
+ - Valid uses of `idle` include:
6
+ - you are temporarily waiting for a new message to continue, or
7
+ - you have finished the current task or step and there is no new task yet.
8
+ - Only use `idle` when the current step is complete, paused, or blocked.
9
+ - Do not use `idle` if you still have an immediate action you can take now.
10
+ - Do not use `idle` instead of replying to a newly received message.
11
+ - After calling `idle`, you will be re-activated when a new message arrives.
12
+ - When that happens, the new message will appear as a fresh input message, and `idle` will return the idle duration.
13
+ """
14
+
15
+ SLEEP_TOOL_GUIDANCE = """\
16
+ ## Sleep Usage Rules
17
+
18
+ - Use `sleep(seconds)` only for deliberate fixed-duration waiting.
19
+ - The `seconds` argument is measured in seconds and may be fractional.
20
+ - While `sleep` is in progress, incoming messages stay queued and are processed after the sleep finishes.
21
+ - Prefer `idle` when you are waiting for an unknown-duration incoming message or handoff.
22
+ - `sleep` returns the actual waited duration when it finishes.
23
+ - Do not use `sleep` instead of replying to a newly received message.
24
+ """
25
+
26
+ TODO_TOOL_GUIDANCE = """\
27
+ ## Todo Tool Rules
28
+
29
+ - Use `todo` to manage your task checklist and track the current plan or remaining work.
30
+ """
31
+
32
+ CREATE_WORKFLOW_TOOL_GUIDANCE = """\
33
+ ## Create Workflow Tool Rules
34
+
35
+ - Use `create_workflow` to open a persistent workflow before building a Workflow Graph for that task.
36
+ - A workflow is the user-visible home for one task. Keep the title concrete and easy to recognize later.
37
+ """
38
+
39
+ DELETE_WORKFLOW_TOOL_GUIDANCE = """\
40
+ ## Delete Workflow Tool Rules
41
+
42
+ - Use `delete_workflow` only when the Human explicitly asks to remove a workflow or when you are intentionally cleaning up a task workspace that should no longer exist.
43
+ - Deleting a workflow permanently removes the workflow and its persisted Workflow Graph after active nodes are terminated.
44
+ """
45
+
46
+ SET_PERMISSIONS_TOOL_GUIDANCE = """\
47
+ ## Set Permissions Tool Rules
48
+
49
+ - Use `set_permissions` to patch a workflow's permission boundary after the workflow already exists.
50
+ - `set_permissions` updates the target workflow by writing directly to its bound Leader's `allow_network` and `write_dirs`.
51
+ - Treat `allow_network` and `write_dirs` as patch fields: omitted fields stay unchanged.
52
+ - When the Human asks to change a workflow's network or writable directory boundary, prefer `set_permissions` instead of delegating that change to the workflow's Leader.
53
+ """
54
+
55
+ CREATE_AGENT_TOOL_GUIDANCE = """\
56
+ ## Create Agent Tool Rules
57
+
58
+ - Use `create_agent` to add a new agent node to the current workflow.
59
+ - Prefer creating the right set of agents up front. If you also have `connect`, wire workflow edges as needed.
60
+ - `create_agent` always creates the new peer in your current workflow. It does not take `workflow_id` or any other cross-workflow target parameter.
61
+ - Ordinary task nodes may use `create_agent` only when that tool was explicitly granted to them.
62
+ - `create_agent` can place the new node as a standalone node, after another node, or between two nodes in the current Workflow Graph.
63
+ - Creating an agent does not start work by itself; explicitly dispatch its first task with `send`.
64
+ - After creating multiple agents, dispatch tasks to all of them before calling `idle`.
65
+ - Do not insert unrelated tool calls or Human-facing text while some planned nodes are still waiting for their first task.
66
+ - When naming an agent via `create_agent`, use title case with spaces (e.g. "Web Researcher", "Code Reviewer", "Data Analyst"). Avoid snake_case, camelCase, or all-lowercase names.
67
+ """
68
+
69
+ DELEGATION_GENERAL_GUIDANCE = """\
70
+ ## Delegation Rules
71
+
72
+ - Treat delegation as a first-choice option, not a last resort.
73
+ - When a task is not really yours to own, your first reaction should be delegation or handoff, not solo execution.
74
+ - Once you conclude delegation is the better path, do it immediately instead of asking the Human whether you should delegate.
75
+ - If delegation can make progress on the Human's request, do not externalize your temporary limitation to the Human before delegating.
76
+ - Before doing the work yourself, first ask whether the task is outside your role, expertise, permissions, available tools, or comparative advantage.
77
+ - If a task is outside your role, expertise, permissions, or current toolset, your default move should be delegation rather than prolonged solo trial-and-error.
78
+ - If you cannot complete a task efficiently or confidently alone, delegate early instead of struggling alone.
79
+ - Do not ask the Human for permission to delegate just because delegation seems helpful; only ask first when the delegation itself would introduce destructive actions, material extra cost, permission risk, or the Human explicitly asked to approve delegation decisions.
80
+ - Do not turn delegation into a suggestion like "I can ask another agent if you want" when you can already delegate now.
81
+ - Do not keep pushing on execution-heavy or specialized work that obviously belongs to a more suitable agent.
82
+ - Do not start with repeated local retries when the better move is obvious delegation.
83
+ - Do not spend multiple turns persisting alone on a clear role mismatch; hand off with a concrete task, expected output, and relevant constraints.
84
+ - After creating or delegating to another agent, keep coordinating the work rather than duplicating the same task yourself.
85
+ - Before calling `idle`, check whether delegation, handoff, or creating another agent is the real next action.
86
+ """
87
+
88
+ CONNECT_TOOL_GUIDANCE = """\
89
+ ## Connect Tool Rules
90
+
91
+ - Use `connect` to create a directed workflow edge between node ports when the current Workflow Graph needs it.
92
+ """
93
+
94
+ CONTACTS_TOOL_GUIDANCE = """\
95
+ ## Contacts Tool Rules
96
+
97
+ - Use `contacts` to inspect the agents you can currently message directly.
98
+ """
99
+
100
+ SEND_TOOL_GUIDANCE = """\
101
+ ## Send Tool Rules
102
+
103
+ - Use `send` for every formal node-to-node message.
104
+ - `send` takes exactly one `target` and one ordered `parts` array.
105
+ - Use `contacts` before `send` when you need to inspect reachable target ids or names.
106
+ - `send.parts` preserves order. Keep text and image parts in the sequence you intend the receiver to see.
107
+ - `@target:` and similar text prefixes inside normal content do not send anything.
108
+ - If multiple nodes need messages in the same turn, call `send` multiple times in sequence.
109
+ """
110
+
111
+ LIST_ROLES_TOOL_GUIDANCE = """\
112
+ ## List Roles Tool Rules
113
+
114
+ - Use `list_roles` to inspect all registered roles and their included or optional tool configuration before choosing what nodes to create.
115
+ """
116
+
117
+ LIST_WORKFLOWS_TOOL_GUIDANCE = """\
118
+ ## List Workflows Tool Rules
119
+
120
+ - Use `list_workflows` to inspect the current persistent workflows.
121
+ - Pass `workflow_id` when you need the detailed node and edge structure for one workflow before changing or continuing its work.
122
+ """
123
+
124
+ LIST_TOOLS_TOOL_GUIDANCE = """\
125
+ ## List Tools Tool Rules
126
+
127
+ - Use `list_tools` to inspect all registered tools in the system, not just the tools currently available to you.
128
+ """
129
+
130
+ MANAGE_TOOLS_GUIDANCE = """\
131
+ ## Management Tool Rules
132
+
133
+ - `manage_providers` manages provider configuration and model catalogs.
134
+ - `manage_roles` manages role configuration.
135
+ - `manage_settings` reads and updates runtime defaults.
136
+ - `manage_prompts` reads and updates the global custom prompt and custom post prompt.
137
+ - `set_permissions` updates an existing workflow's permission boundary.
138
+ """
139
+
140
+ COMMUNICATION_USAGE_GUIDANCE = """\
141
+ ## Communication Rules
142
+
143
+ - Use plain content only for your own direct output. Plain content is never delivered to another node.
144
+ - Use `send` for every formal node-to-node message. Target selection belongs in `send.target`, not in the text body.
145
+ - `send` takes one target at a time. If multiple nodes need messages, call `send` multiple times in sequence.
146
+ - Use `contacts` to discover current contact names and ids before sending.
147
+ - When you finish your assigned task, use `send` to deliver the result to the correct destination before calling `idle`.
148
+ - `@target:` and similar `@name:` text inside normal content are just text. They do not send anything.
149
+ - Do NOT output content just to "think out loud" between tool calls. Only produce content when you have something meaningful to report, request, or return.
150
+ - You receive messages as: <message from="uuid">content</message>
151
+ - Your previously sent messages appear in context as: <message to="uuid">content</message>
152
+ - System context is injected as: <system>content</system>
153
+ """
154
+
155
+ FILE_PATH_GUIDANCE = """\
156
+ ## File Path Rules
157
+
158
+ - Always use relative paths for file operations (read, edit, exec). Do not guess absolute paths like /workspace or /home.
159
+ - If you need the absolute working directory, run `pwd` first.
160
+ """
161
+
162
+ ASSISTANT_ONLY_PROMPT = """\
163
+ ## Assistant-Only Communication Rules
164
+
165
+ - Your content is pushed directly to the frontend chat panel as your reply to the Human.
166
+ - Plain content is your reply to the Human.
167
+ - If you need to send a message to a connected node instead of the Human, use `send`.
168
+ - After replying directly to the Human, if you have no further immediate action, call `idle` in the same response instead of continuing with another text-only turn.
169
+ - Do not repeat or restate a Human-facing reply that you already sent unless you have genuinely new information or a correction.
170
+ - Entering a waiting state still requires an explicit `idle` tool call.
171
+ """
172
+
173
+ DEFAULT_AGENT_ROLE_PROMPT = (
174
+ "You are a helpful agent. Complete the assigned task only when it clearly fits your role and capabilities, "
175
+ "and otherwise delegate or hand it off immediately to the right agent before reporting results back."
176
+ )
177
+
178
+ _MANAGEMENT_TOOL_NAMES = frozenset(
179
+ {
180
+ "manage_providers",
181
+ "manage_roles",
182
+ "manage_settings",
183
+ "manage_prompts",
184
+ }
185
+ )
186
+
187
+
188
+ def _normalize_tools(tools: list[str]) -> set[str]:
189
+ return {tool_name.strip() for tool_name in tools if tool_name.strip()}
190
+
191
+
192
+ def _build_conditional_tool_guidance(tools: list[str]) -> list[str]:
193
+ tool_names = _normalize_tools(tools)
194
+ parts: list[str] = []
195
+
196
+ if "idle" in tool_names:
197
+ parts.append(IDLE_TOOL_GUIDANCE.strip())
198
+ if "sleep" in tool_names:
199
+ parts.append(SLEEP_TOOL_GUIDANCE.strip())
200
+ if "todo" in tool_names:
201
+ parts.append(TODO_TOOL_GUIDANCE.strip())
202
+ if "create_workflow" in tool_names:
203
+ parts.append(CREATE_WORKFLOW_TOOL_GUIDANCE.strip())
204
+ if "delete_workflow" in tool_names:
205
+ parts.append(DELETE_WORKFLOW_TOOL_GUIDANCE.strip())
206
+ if "set_permissions" in tool_names:
207
+ parts.append(SET_PERMISSIONS_TOOL_GUIDANCE.strip())
208
+ if "create_agent" in tool_names:
209
+ parts.append(CREATE_AGENT_TOOL_GUIDANCE.strip())
210
+ if "create_agent" in tool_names:
211
+ parts.append(DELEGATION_GENERAL_GUIDANCE.strip())
212
+ if "connect" in tool_names:
213
+ parts.append(CONNECT_TOOL_GUIDANCE.strip())
214
+ if "contacts" in tool_names:
215
+ parts.append(CONTACTS_TOOL_GUIDANCE.strip())
216
+ if "send" in tool_names:
217
+ parts.append(SEND_TOOL_GUIDANCE.strip())
218
+ if "list_roles" in tool_names:
219
+ parts.append(LIST_ROLES_TOOL_GUIDANCE.strip())
220
+ if "list_workflows" in tool_names:
221
+ parts.append(LIST_WORKFLOWS_TOOL_GUIDANCE.strip())
222
+ if "list_tools" in tool_names:
223
+ parts.append(LIST_TOOLS_TOOL_GUIDANCE.strip())
224
+ if _MANAGEMENT_TOOL_NAMES & tool_names:
225
+ parts.append(MANAGE_TOOLS_GUIDANCE.strip())
226
+ return parts
227
+
228
+
229
+ def compose_system_prompt(
230
+ role_prompt: str,
231
+ custom_prompt: str = "",
232
+ is_assistant: bool = False,
233
+ tools: list[str] | None = None,
234
+ ) -> str:
235
+ custom_prompt_text = custom_prompt.strip()
236
+ role_specific_prompt = role_prompt.strip()
237
+
238
+ parts = [
239
+ COMMUNICATION_USAGE_GUIDANCE.strip(),
240
+ FILE_PATH_GUIDANCE.strip(),
241
+ ]
242
+ if tools is not None:
243
+ parts.extend(_build_conditional_tool_guidance(tools))
244
+ if is_assistant:
245
+ parts.append(ASSISTANT_ONLY_PROMPT.strip())
246
+ if custom_prompt_text:
247
+ parts.append(custom_prompt_text)
248
+ if role_specific_prompt:
249
+ parts.append(role_specific_prompt)
250
+ return "\n\n".join(parts).strip()