flowent 0.0.1 → 0.0.5

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 (484) hide show
  1. package/README.md +20 -9
  2. package/backend/.python-version +1 -0
  3. package/backend/README.md +74 -0
  4. package/backend/pyproject.toml +58 -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__/observability_service.cpython-313.pyc +0 -0
  23. package/backend/src/flowent/__pycache__/registry.cpython-313.pyc +0 -0
  24. package/backend/src/flowent/__pycache__/role_management.cpython-313.pyc +0 -0
  25. package/backend/src/flowent/__pycache__/runtime.cpython-313.pyc +0 -0
  26. package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
  27. package/backend/src/flowent/__pycache__/security.cpython-313.pyc +0 -0
  28. package/backend/src/flowent/__pycache__/settings.cpython-313.pyc +0 -0
  29. package/backend/src/flowent/__pycache__/settings_management.cpython-313.pyc +0 -0
  30. package/backend/src/flowent/__pycache__/state_db.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 +3120 -0
  35. package/backend/src/flowent/assistant_commands.py +115 -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 +2508 -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 +1918 -0
  50. package/backend/src/flowent/model_metadata.py +102 -0
  51. package/backend/src/flowent/models/__init__.py +125 -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 +34 -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 +472 -0
  72. package/backend/src/flowent/models/history.py +272 -0
  73. package/backend/src/flowent/models/llm.py +62 -0
  74. package/backend/src/flowent/models/message.py +33 -0
  75. package/backend/src/flowent/models/tab.py +85 -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/observability_service.py +218 -0
  79. package/backend/src/flowent/prompts/__init__.py +67 -0
  80. package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  81. package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
  82. package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
  83. package/backend/src/flowent/prompts/common.py +250 -0
  84. package/backend/src/flowent/prompts/steward.py +64 -0
  85. package/backend/src/flowent/providers/__init__.py +23 -0
  86. package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  87. package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
  88. package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
  89. package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
  90. package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
  91. package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
  92. package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
  93. package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
  94. package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
  95. package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
  96. package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
  97. package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
  98. package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
  99. package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
  100. package/backend/src/flowent/providers/anthropic.py +468 -0
  101. package/backend/src/flowent/providers/base_url.py +60 -0
  102. package/backend/src/flowent/providers/configuration.py +189 -0
  103. package/backend/src/flowent/providers/content.py +122 -0
  104. package/backend/src/flowent/providers/errors.py +223 -0
  105. package/backend/src/flowent/providers/gateway.py +169 -0
  106. package/backend/src/flowent/providers/gemini.py +447 -0
  107. package/backend/src/flowent/providers/headers.py +20 -0
  108. package/backend/src/flowent/providers/management.py +96 -0
  109. package/backend/src/flowent/providers/ollama.py +293 -0
  110. package/backend/src/flowent/providers/openai.py +422 -0
  111. package/backend/src/flowent/providers/openai_responses.py +655 -0
  112. package/backend/src/flowent/providers/registry.py +144 -0
  113. package/backend/src/flowent/providers/sse.py +31 -0
  114. package/backend/src/flowent/providers/thinking.py +79 -0
  115. package/backend/src/flowent/registry.py +73 -0
  116. package/backend/src/flowent/role_management.py +267 -0
  117. package/backend/src/flowent/routes/__init__.py +28 -0
  118. package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
  119. package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
  120. package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
  121. package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
  122. package/backend/src/flowent/routes/__pycache__/mcp.cpython-313.pyc +0 -0
  123. package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
  124. package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
  125. package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
  126. package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
  127. package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
  128. package/backend/src/flowent/routes/__pycache__/settings.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 +413 -0
  137. package/backend/src/flowent/routes/prompts.py +46 -0
  138. package/backend/src/flowent/routes/providers_route.py +365 -0
  139. package/backend/src/flowent/routes/roles.py +207 -0
  140. package/backend/src/flowent/routes/settings.py +328 -0
  141. package/backend/src/flowent/routes/tabs.py +310 -0
  142. package/backend/src/flowent/routes/ws.py +33 -0
  143. package/backend/src/flowent/runtime.py +165 -0
  144. package/backend/src/flowent/sandbox.py +45 -0
  145. package/backend/src/flowent/security.py +57 -0
  146. package/backend/src/flowent/settings.py +2518 -0
  147. package/backend/src/flowent/settings_management.py +298 -0
  148. package/backend/src/flowent/state_db.py +120 -0
  149. package/backend/src/flowent/static/assets/AssistantPage-VBohhz4d.js +1 -0
  150. package/backend/src/flowent/static/assets/ChannelsPage-CIydPZA_.js +1 -0
  151. package/backend/src/flowent/static/assets/McpPage-CHPm2TPY.js +7 -0
  152. package/backend/src/flowent/static/assets/PageScaffold-DteOA8V7.js +1 -0
  153. package/backend/src/flowent/static/assets/PromptsPage-CSmJ3sZg.js +1 -0
  154. package/backend/src/flowent/static/assets/ProvidersPage-sl2jeG4e.js +3 -0
  155. package/backend/src/flowent/static/assets/RolesPage-DCe7W6Km.js +1 -0
  156. package/backend/src/flowent/static/assets/SettingsPage-Bix9e63E.js +3 -0
  157. package/backend/src/flowent/static/assets/ToolsPage-favNkj5C.js +1 -0
  158. package/backend/src/flowent/static/assets/WorkspaceCommandDialog-DRS6wiD6.js +1 -0
  159. package/backend/src/flowent/static/assets/WorkspacePage-KuaDjt_D.js +3 -0
  160. package/backend/src/flowent/static/assets/WorkspacePanels-BZxBw8M5.js +1 -0
  161. package/backend/src/flowent/static/assets/alert-dialog-DIBUCmqM.js +1 -0
  162. package/backend/src/flowent/static/assets/datetime-eJqd0V2S.js +1 -0
  163. package/backend/src/flowent/static/assets/dialog-BOvHIBrg.js +1 -0
  164. package/backend/src/flowent/static/assets/elk-worker.min-C9JGDOE-.js +6312 -0
  165. package/backend/src/flowent/static/assets/graph-vendor-CHpVij2M.css +1 -0
  166. package/backend/src/flowent/static/assets/graph-vendor-DRq_-6fV.js +7 -0
  167. package/backend/src/flowent/static/assets/index-Biio-CoI.js +10 -0
  168. package/backend/src/flowent/static/assets/index-CmQvO7sl.css +1 -0
  169. package/backend/src/flowent/static/assets/layout.worker-jMHqAFbP.js +24 -0
  170. package/backend/src/flowent/static/assets/markdown-vendor-C9RtvaJh.js +29 -0
  171. package/backend/src/flowent/static/assets/modelParams-DcEhGnu0.js +1 -0
  172. package/backend/src/flowent/static/assets/react-vendor-mEs_JJxa.js +9 -0
  173. package/backend/src/flowent/static/assets/roles-BbIEIMeG.js +1 -0
  174. package/backend/src/flowent/static/assets/rolldown-runtime-BYbx6iT9.js +1 -0
  175. package/backend/src/flowent/static/assets/select-D9SwnlXF.js +1 -0
  176. package/backend/src/flowent/static/assets/surface-Bzr1FRG4.js +1 -0
  177. package/backend/src/flowent/static/assets/triState-DgLlKdRR.js +1 -0
  178. package/backend/src/flowent/static/assets/ui-vendor-UazN8rcv.js +51 -0
  179. package/backend/src/flowent/static/index.html +35 -0
  180. package/backend/src/flowent/tools/__init__.py +275 -0
  181. package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  182. package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
  183. package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
  184. package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
  185. package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
  186. package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
  187. package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
  188. package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
  189. package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
  190. package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
  191. package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
  192. package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
  193. package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
  194. package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
  195. package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
  196. package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
  197. package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
  198. package/backend/src/flowent/tools/__pycache__/mcp.cpython-313.pyc +0 -0
  199. package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
  200. package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
  201. package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
  202. package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
  203. package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
  204. package/backend/src/flowent/tools/connect.py +100 -0
  205. package/backend/src/flowent/tools/contacts.py +22 -0
  206. package/backend/src/flowent/tools/create_agent.py +191 -0
  207. package/backend/src/flowent/tools/create_tab.py +61 -0
  208. package/backend/src/flowent/tools/delete_tab.py +39 -0
  209. package/backend/src/flowent/tools/edit.py +142 -0
  210. package/backend/src/flowent/tools/exec.py +118 -0
  211. package/backend/src/flowent/tools/fetch.py +85 -0
  212. package/backend/src/flowent/tools/idle.py +27 -0
  213. package/backend/src/flowent/tools/list_roles.py +75 -0
  214. package/backend/src/flowent/tools/list_tabs.py +100 -0
  215. package/backend/src/flowent/tools/list_tools.py +28 -0
  216. package/backend/src/flowent/tools/manage_prompts.py +102 -0
  217. package/backend/src/flowent/tools/manage_providers.py +220 -0
  218. package/backend/src/flowent/tools/manage_roles.py +275 -0
  219. package/backend/src/flowent/tools/manage_settings.py +364 -0
  220. package/backend/src/flowent/tools/mcp.py +199 -0
  221. package/backend/src/flowent/tools/read.py +152 -0
  222. package/backend/src/flowent/tools/send.py +68 -0
  223. package/backend/src/flowent/tools/set_permissions.py +99 -0
  224. package/backend/src/flowent/tools/sleep.py +41 -0
  225. package/backend/src/flowent/tools/todo.py +51 -0
  226. package/backend/src/flowent/workspace_store.py +479 -0
  227. package/backend/tests/__init__.py +0 -0
  228. package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  229. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  230. package/backend/tests/conftest.py +6 -0
  231. package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  232. package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
  233. package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
  234. package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
  235. package/backend/tests/integration/api/__pycache__/test_mcp_api.cpython-313-pytest-9.0.3.pyc +0 -0
  236. package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
  237. package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
  238. package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
  239. package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
  240. package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
  241. package/backend/tests/integration/api/conftest.py +29 -0
  242. package/backend/tests/integration/api/test_access_api.py +182 -0
  243. package/backend/tests/integration/api/test_assistant_api.py +354 -0
  244. package/backend/tests/integration/api/test_frontend_mounting.py +61 -0
  245. package/backend/tests/integration/api/test_mcp_api.py +116 -0
  246. package/backend/tests/integration/api/test_meta_api.py +33 -0
  247. package/backend/tests/integration/api/test_nodes_api.py +722 -0
  248. package/backend/tests/integration/api/test_prompts_api.py +47 -0
  249. package/backend/tests/integration/api/test_roles_api.py +228 -0
  250. package/backend/tests/integration/api/test_tabs_api.py +802 -0
  251. package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
  252. package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  253. package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  254. package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
  255. package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
  256. package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
  257. package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
  258. package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  259. package/backend/tests/unit/agent/test_agent_public_api.py +837 -0
  260. package/backend/tests/unit/agent/test_agent_runtime.py +2942 -0
  261. package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
  262. package/backend/tests/unit/channels/test_telegram_channel.py +552 -0
  263. package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  264. package/backend/tests/unit/logging/test_logging.py +132 -0
  265. package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
  266. package/backend/tests/unit/prompts/test_prompts.py +570 -0
  267. package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  268. package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
  269. package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
  270. package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  271. package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
  272. package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
  273. package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
  274. package/backend/tests/unit/providers/test_anthropic_provider.py +185 -0
  275. package/backend/tests/unit/providers/test_errors.py +68 -0
  276. package/backend/tests/unit/providers/test_extract_delta_parts.py +22 -0
  277. package/backend/tests/unit/providers/test_openai_provider.py +139 -0
  278. package/backend/tests/unit/providers/test_openai_responses.py +402 -0
  279. package/backend/tests/unit/providers/test_provider_gateway.py +359 -0
  280. package/backend/tests/unit/providers/test_think_tag_parser.py +36 -0
  281. package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  282. package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
  283. package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  284. package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  285. package/backend/tests/unit/routes/test_prompts_routes.py +104 -0
  286. package/backend/tests/unit/routes/test_providers_route.py +370 -0
  287. package/backend/tests/unit/routes/test_roles_routes.py +535 -0
  288. package/backend/tests/unit/routes/test_settings_routes.py +1142 -0
  289. package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  290. package/backend/tests/unit/runtime/test_bootstrap_runtime.py +1002 -0
  291. package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  292. package/backend/tests/unit/sandbox/test_sandbox_tools.py +78 -0
  293. package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
  294. package/backend/tests/unit/security/test_security.py +124 -0
  295. package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
  296. package/backend/tests/unit/settings/test_settings_roles.py +751 -0
  297. package/backend/tests/unit/test_access.py +45 -0
  298. package/backend/tests/unit/test_cli.py +124 -0
  299. package/backend/tests/unit/test_graph_runtime.py +72 -0
  300. package/backend/tests/unit/test_network.py +51 -0
  301. package/backend/tests/unit/test_state_sqlite_storage.py +159 -0
  302. package/backend/tests/unit/test_workspace_store.py +231 -0
  303. package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  304. package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  305. package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  306. package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  307. package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  308. package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  309. package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  310. package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  311. package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  312. package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  313. package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  314. package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  315. package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  316. package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
  317. package/backend/tests/unit/tools/test_connect_tool.py +228 -0
  318. package/backend/tests/unit/tools/test_create_agent_tool.py +436 -0
  319. package/backend/tests/unit/tools/test_delete_tab_tool.py +116 -0
  320. package/backend/tests/unit/tools/test_edit_tool.py +115 -0
  321. package/backend/tests/unit/tools/test_exec_tool.py +81 -0
  322. package/backend/tests/unit/tools/test_fetch_tool.py +65 -0
  323. package/backend/tests/unit/tools/test_manage_prompts_tool.py +117 -0
  324. package/backend/tests/unit/tools/test_manage_providers_tool.py +460 -0
  325. package/backend/tests/unit/tools/test_manage_roles_tool.py +411 -0
  326. package/backend/tests/unit/tools/test_manage_settings_tool.py +611 -0
  327. package/backend/tests/unit/tools/test_read_tool.py +33 -0
  328. package/backend/tests/unit/tools/test_set_permissions_tool.py +595 -0
  329. package/backend/tests/unit/tools/test_todo_tool.py +37 -0
  330. package/backend/tests/unit/tools/test_tool_registry.py +194 -0
  331. package/backend/uv.lock +1144 -0
  332. package/bin/flowent.mjs +62 -36
  333. package/dist/frontend/assets/AssistantPage-VBohhz4d.js +1 -0
  334. package/dist/frontend/assets/ChannelsPage-CIydPZA_.js +1 -0
  335. package/dist/frontend/assets/McpPage-CHPm2TPY.js +7 -0
  336. package/dist/frontend/assets/PageScaffold-DteOA8V7.js +1 -0
  337. package/dist/frontend/assets/PromptsPage-CSmJ3sZg.js +1 -0
  338. package/dist/frontend/assets/ProvidersPage-sl2jeG4e.js +3 -0
  339. package/dist/frontend/assets/RolesPage-DCe7W6Km.js +1 -0
  340. package/dist/frontend/assets/SettingsPage-Bix9e63E.js +3 -0
  341. package/dist/frontend/assets/ToolsPage-favNkj5C.js +1 -0
  342. package/dist/frontend/assets/WorkspaceCommandDialog-DRS6wiD6.js +1 -0
  343. package/dist/frontend/assets/WorkspacePage-KuaDjt_D.js +3 -0
  344. package/dist/frontend/assets/WorkspacePanels-BZxBw8M5.js +1 -0
  345. package/dist/frontend/assets/alert-dialog-DIBUCmqM.js +1 -0
  346. package/dist/frontend/assets/datetime-eJqd0V2S.js +1 -0
  347. package/dist/frontend/assets/dialog-BOvHIBrg.js +1 -0
  348. package/dist/frontend/assets/elk-worker.min-C9JGDOE-.js +6312 -0
  349. package/dist/frontend/assets/graph-vendor-CHpVij2M.css +1 -0
  350. package/dist/frontend/assets/graph-vendor-DRq_-6fV.js +7 -0
  351. package/dist/frontend/assets/index-Biio-CoI.js +10 -0
  352. package/dist/frontend/assets/index-CmQvO7sl.css +1 -0
  353. package/dist/frontend/assets/layout.worker-jMHqAFbP.js +24 -0
  354. package/dist/frontend/assets/markdown-vendor-C9RtvaJh.js +29 -0
  355. package/dist/frontend/assets/modelParams-DcEhGnu0.js +1 -0
  356. package/dist/frontend/assets/react-vendor-mEs_JJxa.js +9 -0
  357. package/dist/frontend/assets/roles-BbIEIMeG.js +1 -0
  358. package/dist/frontend/assets/rolldown-runtime-BYbx6iT9.js +1 -0
  359. package/dist/frontend/assets/select-D9SwnlXF.js +1 -0
  360. package/dist/frontend/assets/surface-Bzr1FRG4.js +1 -0
  361. package/dist/frontend/assets/triState-DgLlKdRR.js +1 -0
  362. package/dist/frontend/assets/ui-vendor-UazN8rcv.js +51 -0
  363. package/dist/frontend/index.html +35 -0
  364. package/package.json +27 -41
  365. package/dist/.next/BUILD_ID +0 -1
  366. package/dist/.next/app-path-routes-manifest.json +0 -6
  367. package/dist/.next/build-manifest.json +0 -20
  368. package/dist/.next/package.json +0 -1
  369. package/dist/.next/prerender-manifest.json +0 -114
  370. package/dist/.next/required-server-files.json +0 -333
  371. package/dist/.next/routes-manifest.json +0 -69
  372. package/dist/.next/server/app/_global-error/page/app-paths-manifest.json +0 -3
  373. package/dist/.next/server/app/_global-error/page/build-manifest.json +0 -16
  374. package/dist/.next/server/app/_global-error/page/next-font-manifest.json +0 -6
  375. package/dist/.next/server/app/_global-error/page/react-loadable-manifest.json +0 -1
  376. package/dist/.next/server/app/_global-error/page/server-reference-manifest.json +0 -4
  377. package/dist/.next/server/app/_global-error/page.js +0 -9
  378. package/dist/.next/server/app/_global-error/page.js.map +0 -5
  379. package/dist/.next/server/app/_global-error/page.js.nft.json +0 -1
  380. package/dist/.next/server/app/_global-error/page_client-reference-manifest.js +0 -3
  381. package/dist/.next/server/app/_global-error.html +0 -1
  382. package/dist/.next/server/app/_global-error.meta +0 -15
  383. package/dist/.next/server/app/_global-error.rsc +0 -14
  384. package/dist/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +0 -5
  385. package/dist/.next/server/app/_global-error.segments/_full.segment.rsc +0 -14
  386. package/dist/.next/server/app/_global-error.segments/_head.segment.rsc +0 -5
  387. package/dist/.next/server/app/_global-error.segments/_index.segment.rsc +0 -5
  388. package/dist/.next/server/app/_global-error.segments/_tree.segment.rsc +0 -1
  389. package/dist/.next/server/app/_not-found/page/app-paths-manifest.json +0 -3
  390. package/dist/.next/server/app/_not-found/page/build-manifest.json +0 -16
  391. package/dist/.next/server/app/_not-found/page/next-font-manifest.json +0 -10
  392. package/dist/.next/server/app/_not-found/page/react-loadable-manifest.json +0 -1
  393. package/dist/.next/server/app/_not-found/page/server-reference-manifest.json +0 -4
  394. package/dist/.next/server/app/_not-found/page.js +0 -13
  395. package/dist/.next/server/app/_not-found/page.js.map +0 -5
  396. package/dist/.next/server/app/_not-found/page.js.nft.json +0 -1
  397. package/dist/.next/server/app/_not-found/page_client-reference-manifest.js +0 -3
  398. package/dist/.next/server/app/_not-found.html +0 -1
  399. package/dist/.next/server/app/_not-found.meta +0 -16
  400. package/dist/.next/server/app/_not-found.rsc +0 -16
  401. package/dist/.next/server/app/_not-found.segments/_full.segment.rsc +0 -16
  402. package/dist/.next/server/app/_not-found.segments/_head.segment.rsc +0 -6
  403. package/dist/.next/server/app/_not-found.segments/_index.segment.rsc +0 -5
  404. package/dist/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +0 -5
  405. package/dist/.next/server/app/_not-found.segments/_not-found.segment.rsc +0 -5
  406. package/dist/.next/server/app/_not-found.segments/_tree.segment.rsc +0 -2
  407. package/dist/.next/server/app/icon.svg/route/app-paths-manifest.json +0 -3
  408. package/dist/.next/server/app/icon.svg/route/build-manifest.json +0 -9
  409. package/dist/.next/server/app/icon.svg/route.js +0 -6
  410. package/dist/.next/server/app/icon.svg/route.js.map +0 -5
  411. package/dist/.next/server/app/icon.svg/route.js.nft.json +0 -1
  412. package/dist/.next/server/app/icon.svg.meta +0 -1
  413. package/dist/.next/server/app/index.html +0 -1
  414. package/dist/.next/server/app/index.meta +0 -14
  415. package/dist/.next/server/app/index.rsc +0 -15
  416. package/dist/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -5
  417. package/dist/.next/server/app/index.segments/_full.segment.rsc +0 -15
  418. package/dist/.next/server/app/index.segments/_head.segment.rsc +0 -6
  419. package/dist/.next/server/app/index.segments/_index.segment.rsc +0 -5
  420. package/dist/.next/server/app/index.segments/_tree.segment.rsc +0 -3
  421. package/dist/.next/server/app/page/app-paths-manifest.json +0 -3
  422. package/dist/.next/server/app/page/build-manifest.json +0 -16
  423. package/dist/.next/server/app/page/next-font-manifest.json +0 -10
  424. package/dist/.next/server/app/page/react-loadable-manifest.json +0 -1
  425. package/dist/.next/server/app/page/server-reference-manifest.json +0 -4
  426. package/dist/.next/server/app/page.js +0 -14
  427. package/dist/.next/server/app/page.js.map +0 -5
  428. package/dist/.next/server/app/page.js.nft.json +0 -1
  429. package/dist/.next/server/app/page_client-reference-manifest.js +0 -3
  430. package/dist/.next/server/app-paths-manifest.json +0 -6
  431. package/dist/.next/server/chunks/[externals]_next_dist_0arv.vj._.js +0 -3
  432. package/dist/.next/server/chunks/[root-of-the-server]__0vcj1q1._.js +0 -13
  433. package/dist/.next/server/chunks/[turbopack]_runtime.js +0 -903
  434. package/dist/.next/server/chunks/_next-internal_server_app_icon_svg_route_actions_0-0ehc~.js +0 -3
  435. package/dist/.next/server/chunks/ssr/05w9_next_dist_0ihu0u9._.js +0 -6
  436. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_12u3mib._.js +0 -3
  437. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_builtin_forbidden_04fbe_..js +0 -3
  438. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_builtin_global-error_0brpl_..js +0 -3
  439. package/dist/.next/server/chunks/ssr/05w9_next_dist_client_components_builtin_unauthorized_0~2g66g.js +0 -3
  440. package/dist/.next/server/chunks/ssr/05w9_next_dist_esm_build_templates_app-page_0~cyr1_.js +0 -4
  441. package/dist/.next/server/chunks/ssr/05w9_next_dist_esm_build_templates_app-page_1105emf.js +0 -4
  442. package/dist/.next/server/chunks/ssr/05w9_next_dist_esm_build_templates_app-page_11uhyqv.js +0 -4
  443. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0.t9_75._.js +0 -33
  444. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0c0ud_z._.js +0 -3
  445. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0f9_8d4._.js +0 -3
  446. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0l5ko41._.js +0 -19
  447. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0mn6z7i._.js +0 -3
  448. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0npxxst._.js +0 -33
  449. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0qjhaca._.js +0 -3
  450. package/dist/.next/server/chunks/ssr/[root-of-the-server]__0rwgw3s._.js +0 -3
  451. package/dist/.next/server/chunks/ssr/[turbopack]_runtime.js +0 -903
  452. package/dist/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0k77kol.js +0 -3
  453. package/dist/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0eq97pa.js +0 -3
  454. package/dist/.next/server/chunks/ssr/_next-internal_server_app_page_actions_09-gtaw.js +0 -3
  455. package/dist/.next/server/chunks/ssr/node_modules__pnpm_056~6.6._.js +0 -3
  456. package/dist/.next/server/chunks/ssr/node_modules__pnpm_0~j0k.e._.js +0 -33
  457. package/dist/.next/server/functions-config-manifest.json +0 -4
  458. package/dist/.next/server/middleware-build-manifest.js +0 -20
  459. package/dist/.next/server/middleware-manifest.json +0 -6
  460. package/dist/.next/server/next-font-manifest.js +0 -1
  461. package/dist/.next/server/next-font-manifest.json +0 -13
  462. package/dist/.next/server/pages/404.html +0 -1
  463. package/dist/.next/server/pages/500.html +0 -1
  464. package/dist/.next/server/pages-manifest.json +0 -4
  465. package/dist/.next/server/prefetch-hints.json +0 -1
  466. package/dist/.next/server/server-reference-manifest.js +0 -1
  467. package/dist/.next/server/server-reference-manifest.json +0 -5
  468. package/dist/.next/static/SMWpxFVvkpYFxY7uuFvGB/_buildManifest.js +0 -11
  469. package/dist/.next/static/SMWpxFVvkpYFxY7uuFvGB/_clientMiddlewareManifest.js +0 -1
  470. package/dist/.next/static/SMWpxFVvkpYFxY7uuFvGB/_ssgManifest.js +0 -1
  471. package/dist/.next/static/chunks/01qk2~bgf76vu.js +0 -1
  472. package/dist/.next/static/chunks/03~yq9q893hmn.js +0 -1
  473. package/dist/.next/static/chunks/080queev.r2uy.js +0 -31
  474. package/dist/.next/static/chunks/0v3lyuj75aq50.js +0 -1
  475. package/dist/.next/static/chunks/10b~xdx5c-i7s.js +0 -5
  476. package/dist/.next/static/chunks/14gla2ascffgv.css +0 -2
  477. package/dist/.next/static/chunks/turbopack-0m-970~qvs7sc.js +0 -1
  478. package/dist/.next/static/media/7178b3e590c64307-s.11.cyxs5p-0z~.woff2 +0 -0
  479. package/dist/.next/static/media/8a480f0b521d4e75-s.06d3mdzz5bre_.woff2 +0 -0
  480. package/dist/.next/static/media/caa3a2e1cccd8315-s.p.16t1db8_9y2o~.woff2 +0 -0
  481. package/dist/package.json +0 -88
  482. package/dist/server.js +0 -38
  483. /package/{dist/.next/server/app/icon.svg.body → backend/src/flowent/static/favicon.svg} +0 -0
  484. /package/dist/{.next/static/media/icon.0.r~afrtrocz9.svg → frontend/favicon.svg} +0 -0
@@ -0,0 +1,44 @@
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 ContentDelta(Serializable):
10
+ text: str
11
+
12
+
13
+ @dataclass
14
+ class ThinkingDelta(Serializable):
15
+ text: str
16
+
17
+
18
+ @dataclass
19
+ class ToolResultDelta(Serializable):
20
+ tool_call_id: str
21
+ text: str
22
+
23
+
24
+ @dataclass
25
+ class SentMessageDelta(Serializable):
26
+ message_id: str
27
+ to_id: str
28
+ text: str
29
+
30
+
31
+ @dataclass
32
+ class ReceivedMessageDelta(Serializable):
33
+ message_id: str
34
+ from_id: str
35
+ text: str
36
+
37
+
38
+ StreamingDelta = (
39
+ ContentDelta
40
+ | ThinkingDelta
41
+ | ToolResultDelta
42
+ | SentMessageDelta
43
+ | ReceivedMessageDelta
44
+ )
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from dataclasses import dataclass, field
5
+ from enum import StrEnum
6
+ from typing import Any
7
+
8
+
9
+ class EventType(StrEnum):
10
+ TAB_CREATED = "tab_created"
11
+ TAB_UPDATED = "tab_updated"
12
+ TAB_DELETED = "tab_deleted"
13
+ NODE_CREATED = "node_created"
14
+ NODE_STATE_CHANGED = "node_state_changed"
15
+ NODE_TODOS_CHANGED = "node_todos_changed"
16
+ NODE_MESSAGE = "node_message"
17
+ NODE_TERMINATED = "node_terminated"
18
+ NODE_DELETED = "node_deleted"
19
+ NODE_CONNECTED = "node_connected"
20
+ NODE_DISCONNECTED = "node_disconnected"
21
+ ASSISTANT_CONTENT = "assistant_content"
22
+ TOOL_CALLED = "tool_called"
23
+ HISTORY_CLEARED = "history_cleared"
24
+ HISTORY_REPLACED = "history_replaced"
25
+ HISTORY_ENTRY_ADDED = "history_entry_added"
26
+ HISTORY_ENTRY_DELTA = "history_entry_delta"
27
+
28
+
29
+ DISPLAY_EVENTS: set[EventType] = {
30
+ EventType.TAB_CREATED,
31
+ EventType.TAB_UPDATED,
32
+ EventType.TAB_DELETED,
33
+ EventType.NODE_CREATED,
34
+ EventType.NODE_STATE_CHANGED,
35
+ EventType.NODE_TODOS_CHANGED,
36
+ EventType.NODE_MESSAGE,
37
+ EventType.NODE_TERMINATED,
38
+ EventType.NODE_DELETED,
39
+ EventType.NODE_CONNECTED,
40
+ EventType.NODE_DISCONNECTED,
41
+ EventType.ASSISTANT_CONTENT,
42
+ EventType.TOOL_CALLED,
43
+ }
44
+
45
+
46
+ @dataclass
47
+ class Event:
48
+ type: EventType
49
+ agent_id: str
50
+ data: dict[str, Any] = field(default_factory=dict)
51
+ timestamp: float = field(default_factory=time.time)
@@ -0,0 +1,472 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from dataclasses import dataclass, field
5
+ from enum import StrEnum
6
+
7
+ from flowent.models.agent import AgentState, NodeConfig, NodeType
8
+ from flowent.models.history import HistoryEntry, deserialize_history_entries
9
+ from flowent.models.todo import TodoItem
10
+
11
+
12
+ class WorkflowNodeKind(StrEnum):
13
+ TRIGGER = "trigger"
14
+ LLM = "llm"
15
+ AGENT = "agent"
16
+ CODE = "code"
17
+ IF = "if"
18
+ MERGE = "merge"
19
+
20
+
21
+ class PortDirection(StrEnum):
22
+ INPUT = "in"
23
+ OUTPUT = "out"
24
+
25
+
26
+ class PortType(StrEnum):
27
+ PARTS = "parts"
28
+ STRING = "string"
29
+ JSON = "json"
30
+
31
+
32
+ class EdgeKind(StrEnum):
33
+ CONTROL = "control"
34
+ DATA = "data"
35
+ EVENT = "event"
36
+
37
+
38
+ class WorkflowActivationState(StrEnum):
39
+ INACTIVE = "inactive"
40
+ ACTIVE = "active"
41
+
42
+
43
+ def _parse_port_direction(raw_direction: object) -> PortDirection:
44
+ if raw_direction == "input":
45
+ return PortDirection.INPUT
46
+ if raw_direction == "output":
47
+ return PortDirection.OUTPUT
48
+ return PortDirection(str(raw_direction))
49
+
50
+
51
+ def _port_type_from_legacy_kind(raw_kind: object) -> PortType | None:
52
+ try:
53
+ kind = EdgeKind(str(raw_kind))
54
+ except ValueError:
55
+ return None
56
+ if kind == EdgeKind.DATA:
57
+ return PortType.JSON
58
+ return PortType.PARTS
59
+
60
+
61
+ @dataclass
62
+ class NodePosition:
63
+ x: float
64
+ y: float
65
+
66
+ def serialize(self) -> dict[str, float]:
67
+ return {"x": self.x, "y": self.y}
68
+
69
+ @classmethod
70
+ def from_mapping(cls, data: dict[str, object] | None) -> NodePosition | None:
71
+ if not isinstance(data, dict):
72
+ return None
73
+ x = data.get("x")
74
+ y = data.get("y")
75
+ if not isinstance(x, (int, float)) or not isinstance(y, (int, float)):
76
+ return None
77
+ return cls(x=float(x), y=float(y))
78
+
79
+
80
+ @dataclass
81
+ class WorkflowPort:
82
+ key: str
83
+ direction: PortDirection
84
+ type: PortType
85
+ required: bool = False
86
+ multiple: bool = False
87
+
88
+ def serialize(self) -> dict[str, object]:
89
+ return {
90
+ "key": self.key,
91
+ "direction": self.direction.value,
92
+ "type": self.type.value,
93
+ "required": self.required,
94
+ "multiple": self.multiple,
95
+ }
96
+
97
+ @classmethod
98
+ def from_mapping(cls, data: dict[str, object]) -> WorkflowPort | None:
99
+ key = data.get("key")
100
+ direction = data.get("direction")
101
+ port_type = data.get("type")
102
+ if not isinstance(key, str) or not key.strip():
103
+ return None
104
+ try:
105
+ parsed_direction = _parse_port_direction(direction)
106
+ except ValueError:
107
+ return None
108
+ try:
109
+ parsed_type = PortType(str(port_type))
110
+ except ValueError:
111
+ legacy_type = _port_type_from_legacy_kind(data.get("kind"))
112
+ if legacy_type is None:
113
+ return None
114
+ parsed_type = legacy_type
115
+ return cls(
116
+ key=key.strip(),
117
+ direction=parsed_direction,
118
+ type=parsed_type,
119
+ required=bool(data.get("required", False)),
120
+ multiple=bool(data.get("multiple", False)),
121
+ )
122
+
123
+
124
+ @dataclass
125
+ class GraphEdge:
126
+ id: str
127
+ from_node_id: str
128
+ from_port_key: str
129
+ to_node_id: str
130
+ to_port_key: str
131
+ kind: EdgeKind = EdgeKind.CONTROL
132
+ tab_id: str | None = None
133
+ created_at: float = field(default_factory=time.time)
134
+
135
+ def serialize(self) -> dict[str, object]:
136
+ payload: dict[str, object] = {
137
+ "id": self.id,
138
+ "from_node_id": self.from_node_id,
139
+ "from_port_key": self.from_port_key,
140
+ "to_node_id": self.to_node_id,
141
+ "to_port_key": self.to_port_key,
142
+ "created_at": self.created_at,
143
+ }
144
+ if self.tab_id is not None:
145
+ payload["tab_id"] = self.tab_id
146
+ return payload
147
+
148
+ @classmethod
149
+ def from_mapping(cls, data: dict[str, object]) -> GraphEdge:
150
+ created_at = data.get("created_at")
151
+ kind = data.get("kind")
152
+ try:
153
+ parsed_kind = EdgeKind(str(kind))
154
+ except ValueError:
155
+ parsed_kind = EdgeKind.CONTROL
156
+ from_port_key = data.get("from_port_key")
157
+ to_port_key = data.get("to_port_key")
158
+ return cls(
159
+ id=str(data.get("id", "")),
160
+ tab_id=str(data["tab_id"]) if isinstance(data.get("tab_id"), str) else None,
161
+ from_node_id=str(data.get("from_node_id", "")),
162
+ from_port_key=(
163
+ str(from_port_key)
164
+ if isinstance(from_port_key, str) and from_port_key.strip()
165
+ else "out"
166
+ ),
167
+ to_node_id=str(data.get("to_node_id", "")),
168
+ to_port_key=(
169
+ str(to_port_key)
170
+ if isinstance(to_port_key, str) and to_port_key.strip()
171
+ else "in"
172
+ ),
173
+ kind=parsed_kind,
174
+ created_at=created_at
175
+ if isinstance(created_at, (int, float))
176
+ else time.time(),
177
+ )
178
+
179
+
180
+ @dataclass
181
+ class WorkflowNodeDefinition:
182
+ id: str
183
+ type: WorkflowNodeKind
184
+ config: dict[str, object] = field(default_factory=dict)
185
+ inputs: list[WorkflowPort] = field(default_factory=list)
186
+ outputs: list[WorkflowPort] = field(default_factory=list)
187
+
188
+ def serialize(self) -> dict[str, object]:
189
+ return {
190
+ "id": self.id,
191
+ "type": self.type.value,
192
+ "config": dict(self.config),
193
+ "inputs": [port.serialize() for port in self.inputs],
194
+ "outputs": [port.serialize() for port in self.outputs],
195
+ }
196
+
197
+ @classmethod
198
+ def from_mapping(
199
+ cls,
200
+ data: dict[str, object],
201
+ ) -> WorkflowNodeDefinition | None:
202
+ node_id = data.get("id")
203
+ node_type = data.get("type")
204
+ if not isinstance(node_id, str) or not node_id.strip():
205
+ return None
206
+ try:
207
+ parsed_type = WorkflowNodeKind(str(node_type))
208
+ except ValueError:
209
+ return None
210
+ raw_config = data.get("config")
211
+ raw_inputs = data.get("inputs")
212
+ raw_outputs = data.get("outputs")
213
+ return cls(
214
+ id=node_id.strip(),
215
+ type=parsed_type,
216
+ config=dict(raw_config) if isinstance(raw_config, dict) else {},
217
+ inputs=[
218
+ port
219
+ for port in (
220
+ WorkflowPort.from_mapping(item)
221
+ for item in (raw_inputs if isinstance(raw_inputs, list) else [])
222
+ if isinstance(item, dict)
223
+ )
224
+ if port is not None
225
+ ],
226
+ outputs=[
227
+ port
228
+ for port in (
229
+ WorkflowPort.from_mapping(item)
230
+ for item in (raw_outputs if isinstance(raw_outputs, list) else [])
231
+ if isinstance(item, dict)
232
+ )
233
+ if port is not None
234
+ ],
235
+ )
236
+
237
+
238
+ @dataclass
239
+ class WorkflowViewDefinition:
240
+ positions: dict[str, NodePosition] = field(default_factory=dict)
241
+
242
+ def serialize(self) -> dict[str, object]:
243
+ if not self.positions:
244
+ return {}
245
+ return {
246
+ "positions": {
247
+ node_id: position.serialize()
248
+ for node_id, position in self.positions.items()
249
+ }
250
+ }
251
+
252
+ @classmethod
253
+ def from_mapping(cls, data: dict[str, object] | None) -> WorkflowViewDefinition:
254
+ if not isinstance(data, dict):
255
+ return cls()
256
+ raw_positions = data.get("positions")
257
+ if not isinstance(raw_positions, dict):
258
+ return cls()
259
+ positions = {
260
+ str(node_id): position
261
+ for node_id, position in (
262
+ (
263
+ node_id,
264
+ NodePosition.from_mapping(payload),
265
+ )
266
+ for node_id, payload in raw_positions.items()
267
+ if isinstance(node_id, str) and isinstance(payload, dict)
268
+ )
269
+ if position is not None
270
+ }
271
+ return cls(positions=positions)
272
+
273
+
274
+ @dataclass
275
+ class WorkflowDefinition:
276
+ version: int = 1
277
+ nodes: list[WorkflowNodeDefinition] = field(default_factory=list)
278
+ edges: list[GraphEdge] = field(default_factory=list)
279
+ view: WorkflowViewDefinition = field(default_factory=WorkflowViewDefinition)
280
+
281
+ def serialize(self) -> dict[str, object]:
282
+ payload: dict[str, object] = {
283
+ "version": self.version,
284
+ "nodes": [node.serialize() for node in self.nodes],
285
+ "edges": [edge.serialize() for edge in self.edges],
286
+ }
287
+ serialized_view = self.view.serialize()
288
+ if serialized_view:
289
+ payload["view"] = serialized_view
290
+ return payload
291
+
292
+ @classmethod
293
+ def from_mapping(cls, data: dict[str, object] | None) -> WorkflowDefinition:
294
+ if not isinstance(data, dict):
295
+ return cls()
296
+ raw_version = data.get("version")
297
+ raw_nodes = data.get("nodes")
298
+ raw_edges = data.get("edges")
299
+ raw_view = data.get("view")
300
+ return cls(
301
+ version=raw_version
302
+ if isinstance(raw_version, int) and raw_version > 0
303
+ else 1,
304
+ nodes=[
305
+ node
306
+ for node in (
307
+ WorkflowNodeDefinition.from_mapping(item)
308
+ for item in (raw_nodes if isinstance(raw_nodes, list) else [])
309
+ if isinstance(item, dict)
310
+ )
311
+ if node is not None
312
+ ],
313
+ edges=[
314
+ GraphEdge.from_mapping(item)
315
+ for item in (raw_edges if isinstance(raw_edges, list) else [])
316
+ if isinstance(item, dict)
317
+ ],
318
+ view=WorkflowViewDefinition.from_mapping(
319
+ raw_view if isinstance(raw_view, dict) else None
320
+ ),
321
+ )
322
+
323
+ def get_node(self, node_id: str) -> WorkflowNodeDefinition | None:
324
+ return next((node for node in self.nodes if node.id == node_id), None)
325
+
326
+
327
+ @dataclass
328
+ class GraphNodeRecord:
329
+ id: str
330
+ config: NodeConfig
331
+ state: AgentState
332
+ todos: list[TodoItem] = field(default_factory=list)
333
+ history: list[HistoryEntry] = field(default_factory=list)
334
+ execution_context_summary: str = ""
335
+ execution_context_history_cutoff: int = 0
336
+ position: NodePosition | None = None
337
+ created_at: float = field(default_factory=time.time)
338
+ updated_at: float = field(default_factory=time.time)
339
+
340
+ def serialize(self) -> dict[str, object]:
341
+ return {
342
+ "id": self.id,
343
+ "config": {
344
+ "node_type": self.config.node_type.value,
345
+ "role_name": self.config.role_name,
346
+ "tab_id": self.config.tab_id,
347
+ "name": self.config.name,
348
+ "tools": list(self.config.tools),
349
+ "write_dirs": list(self.config.write_dirs),
350
+ "allow_network": self.config.allow_network,
351
+ },
352
+ "state": self.state.value,
353
+ "todos": [item.serialize() for item in self.todos],
354
+ "history": [entry.serialize() for entry in self.history],
355
+ "execution_context_summary": self.execution_context_summary,
356
+ "execution_context_history_cutoff": self.execution_context_history_cutoff,
357
+ "position": self.position.serialize()
358
+ if self.position is not None
359
+ else None,
360
+ "created_at": self.created_at,
361
+ "updated_at": self.updated_at,
362
+ }
363
+
364
+ @classmethod
365
+ def from_mapping(cls, data: dict[str, object]) -> GraphNodeRecord:
366
+ from flowent.settings import (
367
+ build_assistant_write_dirs,
368
+ normalize_tool_names,
369
+ )
370
+
371
+ raw_config = data.get("config")
372
+ config = raw_config if isinstance(raw_config, dict) else {}
373
+ raw_todos = data.get("todos")
374
+ raw_history = data.get("history")
375
+ raw_execution_context_summary = data.get("execution_context_summary")
376
+ raw_execution_context_history_cutoff = data.get(
377
+ "execution_context_history_cutoff"
378
+ )
379
+ created_at = data.get("created_at")
380
+ updated_at = data.get("updated_at")
381
+ raw_state = data.get("state")
382
+
383
+ node_type = config.get("node_type")
384
+ try:
385
+ parsed_node_type = NodeType(str(node_type))
386
+ except ValueError:
387
+ parsed_node_type = NodeType.AGENT
388
+
389
+ try:
390
+ state = AgentState(str(raw_state))
391
+ except ValueError:
392
+ state = AgentState.INITIALIZING
393
+
394
+ todos = []
395
+ if isinstance(raw_todos, list):
396
+ todos = [
397
+ TodoItem(text=str(item.get("text", "")))
398
+ for item in raw_todos
399
+ if isinstance(item, dict)
400
+ ]
401
+
402
+ history_items: list[HistoryEntry] = []
403
+ if isinstance(raw_history, list):
404
+ history_items = deserialize_history_entries(
405
+ [item for item in raw_history if isinstance(item, dict)]
406
+ )
407
+ raw_position = data.get("position")
408
+
409
+ raw_write_dirs = (
410
+ [
411
+ str(item)
412
+ for item in config.get("write_dirs", [])
413
+ if isinstance(item, str)
414
+ ]
415
+ if isinstance(config.get("write_dirs"), list)
416
+ else []
417
+ )
418
+
419
+ return cls(
420
+ id=str(data.get("id", "")),
421
+ config=NodeConfig(
422
+ node_type=parsed_node_type,
423
+ role_name=(
424
+ str(config["role_name"])
425
+ if isinstance(config.get("role_name"), str)
426
+ else None
427
+ ),
428
+ tab_id=str(config["tab_id"])
429
+ if isinstance(config.get("tab_id"), str)
430
+ else None,
431
+ name=str(config["name"])
432
+ if isinstance(config.get("name"), str)
433
+ else None,
434
+ tools=normalize_tool_names(
435
+ [
436
+ str(item)
437
+ for item in config.get("tools", [])
438
+ if isinstance(item, str)
439
+ ]
440
+ if isinstance(config.get("tools"), list)
441
+ else []
442
+ ),
443
+ write_dirs=build_assistant_write_dirs(
444
+ raw_write_dirs,
445
+ field_name="write_dirs",
446
+ ),
447
+ allow_network=bool(config.get("allow_network", False)),
448
+ ),
449
+ state=state,
450
+ todos=todos,
451
+ history=history_items,
452
+ execution_context_summary=(
453
+ str(raw_execution_context_summary)
454
+ if isinstance(raw_execution_context_summary, str)
455
+ else ""
456
+ ),
457
+ execution_context_history_cutoff=(
458
+ raw_execution_context_history_cutoff
459
+ if isinstance(raw_execution_context_history_cutoff, int)
460
+ and raw_execution_context_history_cutoff >= 0
461
+ else 0
462
+ ),
463
+ position=NodePosition.from_mapping(
464
+ raw_position if isinstance(raw_position, dict) else None
465
+ ),
466
+ created_at=created_at
467
+ if isinstance(created_at, (int, float))
468
+ else time.time(),
469
+ updated_at=updated_at
470
+ if isinstance(updated_at, (int, float))
471
+ else time.time(),
472
+ )