flowent 0.0.7 → 0.0.10

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 (386) hide show
  1. package/README.md +0 -3
  2. package/backend/README.md +0 -3
  3. package/backend/pyproject.toml +2 -8
  4. package/backend/src/flowent/__pycache__/__init__.cpython-313.pyc +0 -0
  5. package/backend/src/flowent/__pycache__/agent.cpython-313.pyc +0 -0
  6. package/backend/src/flowent/__pycache__/cli.cpython-313.pyc +0 -0
  7. package/backend/src/flowent/__pycache__/context.cpython-313.pyc +0 -0
  8. package/backend/src/flowent/__pycache__/llm.cpython-313.pyc +0 -0
  9. package/backend/src/flowent/__pycache__/logging.cpython-313.pyc +0 -0
  10. package/backend/src/flowent/__pycache__/main.cpython-313.pyc +0 -0
  11. package/backend/src/flowent/__pycache__/patch.cpython-313.pyc +0 -0
  12. package/backend/src/flowent/__pycache__/paths.cpython-313.pyc +0 -0
  13. package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
  14. package/backend/src/flowent/__pycache__/storage.cpython-313.pyc +0 -0
  15. package/backend/src/flowent/__pycache__/tools.cpython-313.pyc +0 -0
  16. package/backend/src/flowent/agent.py +213 -3173
  17. package/backend/src/flowent/cli.py +19 -24
  18. package/backend/src/flowent/context.py +127 -0
  19. package/backend/src/flowent/llm.py +256 -0
  20. package/backend/src/flowent/logging.py +170 -129
  21. package/backend/src/flowent/main.py +321 -70
  22. package/backend/src/flowent/patch.py +182 -0
  23. package/backend/src/flowent/paths.py +11 -0
  24. package/backend/src/flowent/sandbox.py +214 -40
  25. package/backend/src/flowent/static/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
  26. package/backend/src/flowent/static/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
  27. package/backend/src/flowent/static/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
  28. package/backend/src/flowent/static/assets/index-C76K95ty.js +81 -0
  29. package/backend/src/flowent/static/assets/index-iUMNKvlU.css +2 -0
  30. package/backend/src/flowent/static/flowent.png +0 -0
  31. package/backend/src/flowent/static/index.html +5 -25
  32. package/backend/src/flowent/storage.py +302 -0
  33. package/backend/src/flowent/tools.py +364 -0
  34. package/backend/tests/__pycache__/test_agent_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  35. package/backend/tests/__pycache__/test_health.cpython-313-pytest-9.0.3.pyc +0 -0
  36. package/backend/tests/__pycache__/test_llm_providers.cpython-313-pytest-9.0.3.pyc +0 -0
  37. package/backend/tests/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  38. package/backend/tests/__pycache__/test_persistence.cpython-313-pytest-9.0.3.pyc +0 -0
  39. package/backend/tests/__pycache__/test_workspace_chat.cpython-313-pytest-9.0.3.pyc +0 -0
  40. package/backend/tests/test_agent_tools.py +449 -0
  41. package/backend/tests/test_health.py +12 -0
  42. package/backend/tests/test_llm_providers.py +113 -0
  43. package/backend/tests/test_logging.py +182 -0
  44. package/backend/tests/test_persistence.py +125 -0
  45. package/backend/tests/test_workspace_chat.py +578 -0
  46. package/backend/uv.lock +803 -99
  47. package/dist/frontend/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
  48. package/dist/frontend/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
  49. package/dist/frontend/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
  50. package/dist/frontend/assets/index-C76K95ty.js +81 -0
  51. package/dist/frontend/assets/index-iUMNKvlU.css +2 -0
  52. package/dist/frontend/flowent.png +0 -0
  53. package/dist/frontend/index.html +5 -25
  54. package/package.json +1 -2
  55. package/backend/src/flowent/__pycache__/_version.cpython-313.pyc +0 -0
  56. package/backend/src/flowent/__pycache__/access.cpython-313.pyc +0 -0
  57. package/backend/src/flowent/__pycache__/assistant_commands.cpython-313.pyc +0 -0
  58. package/backend/src/flowent/__pycache__/config.cpython-313.pyc +0 -0
  59. package/backend/src/flowent/__pycache__/events.cpython-313.pyc +0 -0
  60. package/backend/src/flowent/__pycache__/graph_runtime.cpython-313.pyc +0 -0
  61. package/backend/src/flowent/__pycache__/graph_service.cpython-313.pyc +0 -0
  62. package/backend/src/flowent/__pycache__/image_assets.cpython-313.pyc +0 -0
  63. package/backend/src/flowent/__pycache__/model_metadata.cpython-313.pyc +0 -0
  64. package/backend/src/flowent/__pycache__/network.cpython-313.pyc +0 -0
  65. package/backend/src/flowent/__pycache__/observability_service.cpython-313.pyc +0 -0
  66. package/backend/src/flowent/__pycache__/registry.cpython-313.pyc +0 -0
  67. package/backend/src/flowent/__pycache__/role_management.cpython-313.pyc +0 -0
  68. package/backend/src/flowent/__pycache__/runtime.cpython-313.pyc +0 -0
  69. package/backend/src/flowent/__pycache__/security.cpython-313.pyc +0 -0
  70. package/backend/src/flowent/__pycache__/settings.cpython-313.pyc +0 -0
  71. package/backend/src/flowent/__pycache__/settings_management.cpython-313.pyc +0 -0
  72. package/backend/src/flowent/__pycache__/state_db.cpython-313.pyc +0 -0
  73. package/backend/src/flowent/__pycache__/workspace_store.cpython-313.pyc +0 -0
  74. package/backend/src/flowent/access.py +0 -247
  75. package/backend/src/flowent/assistant_commands.py +0 -115
  76. package/backend/src/flowent/channels/__init__.py +0 -3
  77. package/backend/src/flowent/channels/__pycache__/__init__.cpython-313.pyc +0 -0
  78. package/backend/src/flowent/channels/__pycache__/telegram.cpython-313.pyc +0 -0
  79. package/backend/src/flowent/channels/telegram.py +0 -615
  80. package/backend/src/flowent/config.py +0 -14
  81. package/backend/src/flowent/dev.py +0 -3
  82. package/backend/src/flowent/events.py +0 -157
  83. package/backend/src/flowent/graph_runtime.py +0 -60
  84. package/backend/src/flowent/graph_service.py +0 -2401
  85. package/backend/src/flowent/image_assets.py +0 -356
  86. package/backend/src/flowent/model_metadata.py +0 -102
  87. package/backend/src/flowent/models/__init__.py +0 -125
  88. package/backend/src/flowent/models/__pycache__/__init__.cpython-313.pyc +0 -0
  89. package/backend/src/flowent/models/__pycache__/agent.cpython-313.pyc +0 -0
  90. package/backend/src/flowent/models/__pycache__/base.cpython-313.pyc +0 -0
  91. package/backend/src/flowent/models/__pycache__/blueprint.cpython-313.pyc +0 -0
  92. package/backend/src/flowent/models/__pycache__/content.cpython-313.pyc +0 -0
  93. package/backend/src/flowent/models/__pycache__/delta.cpython-313.pyc +0 -0
  94. package/backend/src/flowent/models/__pycache__/event.cpython-313.pyc +0 -0
  95. package/backend/src/flowent/models/__pycache__/graph.cpython-313.pyc +0 -0
  96. package/backend/src/flowent/models/__pycache__/history.cpython-313.pyc +0 -0
  97. package/backend/src/flowent/models/__pycache__/llm.cpython-313.pyc +0 -0
  98. package/backend/src/flowent/models/__pycache__/message.cpython-313.pyc +0 -0
  99. package/backend/src/flowent/models/__pycache__/tab.cpython-313.pyc +0 -0
  100. package/backend/src/flowent/models/__pycache__/todo.cpython-313.pyc +0 -0
  101. package/backend/src/flowent/models/agent.py +0 -34
  102. package/backend/src/flowent/models/base.py +0 -24
  103. package/backend/src/flowent/models/blueprint.py +0 -176
  104. package/backend/src/flowent/models/content.py +0 -164
  105. package/backend/src/flowent/models/delta.py +0 -44
  106. package/backend/src/flowent/models/event.py +0 -51
  107. package/backend/src/flowent/models/graph.py +0 -472
  108. package/backend/src/flowent/models/history.py +0 -272
  109. package/backend/src/flowent/models/llm.py +0 -62
  110. package/backend/src/flowent/models/message.py +0 -33
  111. package/backend/src/flowent/models/tab.py +0 -85
  112. package/backend/src/flowent/models/todo.py +0 -10
  113. package/backend/src/flowent/network.py +0 -146
  114. package/backend/src/flowent/observability_service.py +0 -218
  115. package/backend/src/flowent/prompts/__init__.py +0 -67
  116. package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  117. package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
  118. package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
  119. package/backend/src/flowent/prompts/common.py +0 -250
  120. package/backend/src/flowent/prompts/steward.py +0 -64
  121. package/backend/src/flowent/providers/__init__.py +0 -23
  122. package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  123. package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
  124. package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
  125. package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
  126. package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
  127. package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
  128. package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
  129. package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
  130. package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
  131. package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
  132. package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
  133. package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
  134. package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
  135. package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
  136. package/backend/src/flowent/providers/anthropic.py +0 -468
  137. package/backend/src/flowent/providers/base_url.py +0 -60
  138. package/backend/src/flowent/providers/configuration.py +0 -189
  139. package/backend/src/flowent/providers/content.py +0 -122
  140. package/backend/src/flowent/providers/errors.py +0 -223
  141. package/backend/src/flowent/providers/gateway.py +0 -169
  142. package/backend/src/flowent/providers/gemini.py +0 -447
  143. package/backend/src/flowent/providers/headers.py +0 -20
  144. package/backend/src/flowent/providers/management.py +0 -96
  145. package/backend/src/flowent/providers/ollama.py +0 -293
  146. package/backend/src/flowent/providers/openai.py +0 -422
  147. package/backend/src/flowent/providers/openai_responses.py +0 -655
  148. package/backend/src/flowent/providers/registry.py +0 -144
  149. package/backend/src/flowent/providers/sse.py +0 -31
  150. package/backend/src/flowent/providers/thinking.py +0 -79
  151. package/backend/src/flowent/registry.py +0 -73
  152. package/backend/src/flowent/role_management.py +0 -270
  153. package/backend/src/flowent/routes/__init__.py +0 -26
  154. package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
  155. package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
  156. package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
  157. package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
  158. package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
  159. package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
  160. package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
  161. package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
  162. package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
  163. package/backend/src/flowent/routes/__pycache__/settings.cpython-313.pyc +0 -0
  164. package/backend/src/flowent/routes/__pycache__/tabs.cpython-313.pyc +0 -0
  165. package/backend/src/flowent/routes/__pycache__/ws.cpython-313.pyc +0 -0
  166. package/backend/src/flowent/routes/access.py +0 -48
  167. package/backend/src/flowent/routes/assistant.py +0 -158
  168. package/backend/src/flowent/routes/image_assets.py +0 -33
  169. package/backend/src/flowent/routes/meta.py +0 -28
  170. package/backend/src/flowent/routes/nodes.py +0 -423
  171. package/backend/src/flowent/routes/prompts.py +0 -46
  172. package/backend/src/flowent/routes/providers_route.py +0 -365
  173. package/backend/src/flowent/routes/roles.py +0 -207
  174. package/backend/src/flowent/routes/settings.py +0 -379
  175. package/backend/src/flowent/routes/tabs.py +0 -298
  176. package/backend/src/flowent/routes/ws.py +0 -33
  177. package/backend/src/flowent/runtime.py +0 -160
  178. package/backend/src/flowent/security.py +0 -37
  179. package/backend/src/flowent/settings.py +0 -2112
  180. package/backend/src/flowent/settings_management.py +0 -394
  181. package/backend/src/flowent/state_db.py +0 -108
  182. package/backend/src/flowent/static/assets/AssistantPage-BW7XAd9I.js +0 -1
  183. package/backend/src/flowent/static/assets/ChannelsPage-tCJHgt6m.js +0 -1
  184. package/backend/src/flowent/static/assets/PageScaffold-f6g2l7XN.js +0 -1
  185. package/backend/src/flowent/static/assets/PromptsPage-C3Sxn2D7.js +0 -1
  186. package/backend/src/flowent/static/assets/ProvidersPage-BfmdXmNt.js +0 -3
  187. package/backend/src/flowent/static/assets/RolesPage-DET8wO4r.js +0 -1
  188. package/backend/src/flowent/static/assets/SettingsPage-D-g3deMm.js +0 -3
  189. package/backend/src/flowent/static/assets/ToolsPage-CDmtE2g4.js +0 -1
  190. package/backend/src/flowent/static/assets/WorkspacePage-AZsJ0sD0.js +0 -3
  191. package/backend/src/flowent/static/assets/WorkspacePanels-CteCjolX.js +0 -1
  192. package/backend/src/flowent/static/assets/alert-dialog-Duorp_S-.js +0 -1
  193. package/backend/src/flowent/static/assets/dialog-C3ixjGjN.js +0 -1
  194. package/backend/src/flowent/static/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  195. package/backend/src/flowent/static/assets/graph-vendor-CHpVij2M.css +0 -1
  196. package/backend/src/flowent/static/assets/graph-vendor-DRq_-6fV.js +0 -7
  197. package/backend/src/flowent/static/assets/index--o_0fv0N.css +0 -1
  198. package/backend/src/flowent/static/assets/index-C9HuekJm.js +0 -10
  199. package/backend/src/flowent/static/assets/layout.worker-jMHqAFbP.js +0 -24
  200. package/backend/src/flowent/static/assets/markdown-vendor-C9RtvaJh.js +0 -29
  201. package/backend/src/flowent/static/assets/modelParams-DmnF2hwR.js +0 -1
  202. package/backend/src/flowent/static/assets/providerTypes-DT3Ahwl_.js +0 -1
  203. package/backend/src/flowent/static/assets/react-vendor-mEs_JJxa.js +0 -9
  204. package/backend/src/flowent/static/assets/roles-CuRT_chR.js +0 -1
  205. package/backend/src/flowent/static/assets/rolldown-runtime-BYbx6iT9.js +0 -1
  206. package/backend/src/flowent/static/assets/select-DCfeNu-F.js +0 -1
  207. package/backend/src/flowent/static/assets/surface-pWwG5ogx.js +0 -1
  208. package/backend/src/flowent/static/assets/ui-vendor-C5pJa8N7.js +0 -51
  209. package/backend/src/flowent/static/assets/useAppRoute-FgSHBKhV.js +0 -1
  210. package/backend/src/flowent/static/favicon.svg +0 -4
  211. package/backend/src/flowent/tools/__init__.py +0 -176
  212. package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  213. package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
  214. package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
  215. package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
  216. package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
  217. package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
  218. package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
  219. package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
  220. package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
  221. package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
  222. package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
  223. package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
  224. package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
  225. package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
  226. package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
  227. package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
  228. package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
  229. package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
  230. package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
  231. package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
  232. package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
  233. package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
  234. package/backend/src/flowent/tools/connect.py +0 -100
  235. package/backend/src/flowent/tools/contacts.py +0 -22
  236. package/backend/src/flowent/tools/create_agent.py +0 -191
  237. package/backend/src/flowent/tools/create_tab.py +0 -61
  238. package/backend/src/flowent/tools/delete_tab.py +0 -39
  239. package/backend/src/flowent/tools/edit.py +0 -142
  240. package/backend/src/flowent/tools/exec.py +0 -118
  241. package/backend/src/flowent/tools/fetch.py +0 -85
  242. package/backend/src/flowent/tools/idle.py +0 -27
  243. package/backend/src/flowent/tools/list_roles.py +0 -68
  244. package/backend/src/flowent/tools/list_tabs.py +0 -100
  245. package/backend/src/flowent/tools/list_tools.py +0 -28
  246. package/backend/src/flowent/tools/manage_prompts.py +0 -102
  247. package/backend/src/flowent/tools/manage_providers.py +0 -220
  248. package/backend/src/flowent/tools/manage_roles.py +0 -275
  249. package/backend/src/flowent/tools/manage_settings.py +0 -326
  250. package/backend/src/flowent/tools/read.py +0 -152
  251. package/backend/src/flowent/tools/send.py +0 -68
  252. package/backend/src/flowent/tools/set_permissions.py +0 -99
  253. package/backend/src/flowent/tools/sleep.py +0 -41
  254. package/backend/src/flowent/tools/todo.py +0 -51
  255. package/backend/src/flowent/workspace_store.py +0 -479
  256. package/backend/tests/__init__.py +0 -0
  257. package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  258. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  259. package/backend/tests/conftest.py +0 -6
  260. package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  261. package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
  262. package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
  263. package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
  264. package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
  265. package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
  266. package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
  267. package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
  268. package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
  269. package/backend/tests/integration/api/conftest.py +0 -29
  270. package/backend/tests/integration/api/test_access_api.py +0 -182
  271. package/backend/tests/integration/api/test_assistant_api.py +0 -422
  272. package/backend/tests/integration/api/test_frontend_mounting.py +0 -61
  273. package/backend/tests/integration/api/test_meta_api.py +0 -32
  274. package/backend/tests/integration/api/test_nodes_api.py +0 -787
  275. package/backend/tests/integration/api/test_prompts_api.py +0 -47
  276. package/backend/tests/integration/api/test_roles_api.py +0 -228
  277. package/backend/tests/integration/api/test_tabs_api.py +0 -688
  278. package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
  279. package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  280. package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  281. package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
  282. package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
  283. package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
  284. package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
  285. package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  286. package/backend/tests/unit/agent/test_agent_public_api.py +0 -822
  287. package/backend/tests/unit/agent/test_agent_runtime.py +0 -3088
  288. package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
  289. package/backend/tests/unit/channels/test_telegram_channel.py +0 -552
  290. package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  291. package/backend/tests/unit/logging/test_logging.py +0 -132
  292. package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
  293. package/backend/tests/unit/prompts/test_prompts.py +0 -570
  294. package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  295. package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
  296. package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
  297. package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  298. package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
  299. package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
  300. package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
  301. package/backend/tests/unit/providers/test_anthropic_provider.py +0 -185
  302. package/backend/tests/unit/providers/test_errors.py +0 -68
  303. package/backend/tests/unit/providers/test_extract_delta_parts.py +0 -22
  304. package/backend/tests/unit/providers/test_openai_provider.py +0 -139
  305. package/backend/tests/unit/providers/test_openai_responses.py +0 -402
  306. package/backend/tests/unit/providers/test_provider_gateway.py +0 -359
  307. package/backend/tests/unit/providers/test_think_tag_parser.py +0 -36
  308. package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  309. package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
  310. package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  311. package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  312. package/backend/tests/unit/routes/test_prompts_routes.py +0 -82
  313. package/backend/tests/unit/routes/test_providers_route.py +0 -370
  314. package/backend/tests/unit/routes/test_roles_routes.py +0 -539
  315. package/backend/tests/unit/routes/test_settings_routes.py +0 -1123
  316. package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  317. package/backend/tests/unit/runtime/test_bootstrap_runtime.py +0 -1002
  318. package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  319. package/backend/tests/unit/sandbox/test_sandbox_tools.py +0 -78
  320. package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
  321. package/backend/tests/unit/security/test_security.py +0 -124
  322. package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
  323. package/backend/tests/unit/settings/test_settings_roles.py +0 -703
  324. package/backend/tests/unit/test_access.py +0 -45
  325. package/backend/tests/unit/test_cli.py +0 -102
  326. package/backend/tests/unit/test_graph_runtime.py +0 -72
  327. package/backend/tests/unit/test_network.py +0 -51
  328. package/backend/tests/unit/test_state_sqlite_storage.py +0 -87
  329. package/backend/tests/unit/test_workspace_store.py +0 -228
  330. package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  331. package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  332. package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  333. package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  334. package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  335. package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  336. package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  337. package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  338. package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  339. package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  340. package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  341. package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  342. package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  343. package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
  344. package/backend/tests/unit/tools/test_connect_tool.py +0 -228
  345. package/backend/tests/unit/tools/test_create_agent_tool.py +0 -404
  346. package/backend/tests/unit/tools/test_delete_tab_tool.py +0 -116
  347. package/backend/tests/unit/tools/test_edit_tool.py +0 -115
  348. package/backend/tests/unit/tools/test_exec_tool.py +0 -81
  349. package/backend/tests/unit/tools/test_fetch_tool.py +0 -65
  350. package/backend/tests/unit/tools/test_manage_prompts_tool.py +0 -92
  351. package/backend/tests/unit/tools/test_manage_providers_tool.py +0 -460
  352. package/backend/tests/unit/tools/test_manage_roles_tool.py +0 -411
  353. package/backend/tests/unit/tools/test_manage_settings_tool.py +0 -611
  354. package/backend/tests/unit/tools/test_read_tool.py +0 -33
  355. package/backend/tests/unit/tools/test_set_permissions_tool.py +0 -595
  356. package/backend/tests/unit/tools/test_todo_tool.py +0 -37
  357. package/backend/tests/unit/tools/test_tool_registry.py +0 -199
  358. package/dist/frontend/assets/AssistantPage-BW7XAd9I.js +0 -1
  359. package/dist/frontend/assets/ChannelsPage-tCJHgt6m.js +0 -1
  360. package/dist/frontend/assets/PageScaffold-f6g2l7XN.js +0 -1
  361. package/dist/frontend/assets/PromptsPage-C3Sxn2D7.js +0 -1
  362. package/dist/frontend/assets/ProvidersPage-BfmdXmNt.js +0 -3
  363. package/dist/frontend/assets/RolesPage-DET8wO4r.js +0 -1
  364. package/dist/frontend/assets/SettingsPage-D-g3deMm.js +0 -3
  365. package/dist/frontend/assets/ToolsPage-CDmtE2g4.js +0 -1
  366. package/dist/frontend/assets/WorkspacePage-AZsJ0sD0.js +0 -3
  367. package/dist/frontend/assets/WorkspacePanels-CteCjolX.js +0 -1
  368. package/dist/frontend/assets/alert-dialog-Duorp_S-.js +0 -1
  369. package/dist/frontend/assets/dialog-C3ixjGjN.js +0 -1
  370. package/dist/frontend/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  371. package/dist/frontend/assets/graph-vendor-CHpVij2M.css +0 -1
  372. package/dist/frontend/assets/graph-vendor-DRq_-6fV.js +0 -7
  373. package/dist/frontend/assets/index--o_0fv0N.css +0 -1
  374. package/dist/frontend/assets/index-C9HuekJm.js +0 -10
  375. package/dist/frontend/assets/layout.worker-jMHqAFbP.js +0 -24
  376. package/dist/frontend/assets/markdown-vendor-C9RtvaJh.js +0 -29
  377. package/dist/frontend/assets/modelParams-DmnF2hwR.js +0 -1
  378. package/dist/frontend/assets/providerTypes-DT3Ahwl_.js +0 -1
  379. package/dist/frontend/assets/react-vendor-mEs_JJxa.js +0 -9
  380. package/dist/frontend/assets/roles-CuRT_chR.js +0 -1
  381. package/dist/frontend/assets/rolldown-runtime-BYbx6iT9.js +0 -1
  382. package/dist/frontend/assets/select-DCfeNu-F.js +0 -1
  383. package/dist/frontend/assets/surface-pWwG5ogx.js +0 -1
  384. package/dist/frontend/assets/ui-vendor-C5pJa8N7.js +0 -51
  385. package/dist/frontend/assets/useAppRoute-FgSHBKhV.js +0 -1
  386. package/dist/frontend/favicon.svg +0 -4
@@ -1,51 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- from typing import TYPE_CHECKING, Any, ClassVar
5
-
6
- from flowent.events import event_bus
7
- from flowent.models import Event, EventType, TodoItem
8
- from flowent.tools import Tool
9
-
10
- if TYPE_CHECKING:
11
- from flowent.agent import Agent
12
-
13
-
14
- class TodoTool(Tool):
15
- name = "todo"
16
- description = "Replace the full todo list with a new ordered list of task strings."
17
- parameters: ClassVar[dict[str, Any]] = {
18
- "type": "object",
19
- "properties": {
20
- "todos": {
21
- "type": "array",
22
- "items": {"type": "string"},
23
- "description": "Complete replacement todo list. Pass an empty array to clear all todos.",
24
- },
25
- },
26
- "required": ["todos"],
27
- }
28
-
29
- def execute(self, agent: Agent, args: dict[str, Any], **_kwargs: Any) -> str:
30
- raw_todos = args["todos"]
31
- if not isinstance(raw_todos, list) or not all(
32
- isinstance(item, str) for item in raw_todos
33
- ):
34
- return json.dumps({"error": "todos must be an array of strings"})
35
-
36
- next_todos = [TodoItem(text=item) for item in raw_todos]
37
- agent.set_todos(next_todos)
38
- self._emit_todo_event(agent)
39
- return json.dumps({"status": "updated"})
40
-
41
- @staticmethod
42
- def _emit_todo_event(agent: Agent) -> None:
43
- event_bus.emit(
44
- Event(
45
- type=EventType.NODE_TODOS_CHANGED,
46
- agent_id=agent.uuid,
47
- data={
48
- "todos": [t.serialize() for t in agent.get_todos_snapshot()],
49
- },
50
- ),
51
- )
@@ -1,479 +0,0 @@
1
- from __future__ import annotations
2
-
3
- import json
4
- import threading
5
- import time
6
- from dataclasses import dataclass, field
7
-
8
- from flowent.models import (
9
- AgentBlueprint,
10
- BlueprintVersionSummary,
11
- GraphEdge,
12
- GraphNodeRecord,
13
- NodeType,
14
- Tab,
15
- WorkflowDefinition,
16
- WorkflowNodeKind,
17
- )
18
- from flowent.state_db import get_legacy_workspace_file_path, open_state_db
19
-
20
-
21
- @dataclass
22
- class WorkspaceSnapshot:
23
- tabs: dict[str, Tab] = field(default_factory=dict)
24
- nodes: dict[str, GraphNodeRecord] = field(default_factory=dict)
25
- edges: dict[str, GraphEdge] = field(default_factory=dict)
26
- blueprints: dict[str, AgentBlueprint] = field(default_factory=dict)
27
-
28
- def serialize(self) -> dict[str, object]:
29
- return {
30
- "tabs": [tab.serialize() for tab in self.tabs.values()],
31
- "nodes": [node.serialize() for node in self.nodes.values()],
32
- "edges": [edge.serialize() for edge in self.edges.values()],
33
- "blueprints": [
34
- blueprint.serialize() for blueprint in self.blueprints.values()
35
- ],
36
- }
37
-
38
- @classmethod
39
- def from_mapping(cls, data: dict[str, object]) -> WorkspaceSnapshot:
40
- from flowent.graph_service import build_workflow_node_definition
41
-
42
- raw_tabs = data.get("tabs")
43
- raw_nodes = data.get("nodes")
44
- raw_edges = data.get("edges")
45
- raw_blueprints = data.get("blueprints")
46
- tabs = {
47
- tab.id: tab
48
- for tab in (
49
- Tab.from_mapping(item)
50
- for item in (raw_tabs if isinstance(raw_tabs, list) else [])
51
- if isinstance(item, dict)
52
- )
53
- }
54
- nodes = {
55
- node.id: node
56
- for node in (
57
- GraphNodeRecord.from_mapping(item)
58
- for item in (raw_nodes if isinstance(raw_nodes, list) else [])
59
- if isinstance(item, dict)
60
- )
61
- }
62
- edges = {
63
- edge.id: edge
64
- for edge in (
65
- GraphEdge.from_mapping(item)
66
- for item in (raw_edges if isinstance(raw_edges, list) else [])
67
- if isinstance(item, dict)
68
- )
69
- }
70
- blueprints = {
71
- blueprint.id: blueprint
72
- for blueprint in (
73
- AgentBlueprint.from_mapping(item)
74
- for item in (raw_blueprints if isinstance(raw_blueprints, list) else [])
75
- if isinstance(item, dict)
76
- )
77
- if blueprint.id
78
- }
79
- for tab in tabs.values():
80
- if not isinstance(tab.definition, WorkflowDefinition):
81
- tab.definition = WorkflowDefinition()
82
- tab_node_records = sorted(
83
- [
84
- node
85
- for node in nodes.values()
86
- if node.config.tab_id == tab.id and tab.leader_id != node.id
87
- ],
88
- key=lambda node: (node.created_at, node.id),
89
- )
90
- if not tab.definition.nodes:
91
- migrated_nodes = []
92
- for node in tab_node_records:
93
- if node.config.node_type != NodeType.AGENT:
94
- continue
95
- migrated_nodes.append(
96
- build_workflow_node_definition(
97
- node_id=node.id,
98
- node_kind=WorkflowNodeKind.AGENT,
99
- config={
100
- "role_name": node.config.role_name or "",
101
- **(
102
- {"name": node.config.name}
103
- if node.config.name is not None
104
- else {}
105
- ),
106
- },
107
- )
108
- )
109
- tab.definition.nodes = migrated_nodes
110
- known_node_ids = {node.id for node in tab.definition.nodes}
111
- if not tab.definition.edges:
112
- tab.definition.edges = [
113
- GraphEdge(
114
- id=edge.id,
115
- tab_id=tab.id,
116
- from_node_id=edge.from_node_id,
117
- from_port_key=edge.from_port_key,
118
- to_node_id=edge.to_node_id,
119
- to_port_key=edge.to_port_key,
120
- kind=edge.kind,
121
- created_at=edge.created_at,
122
- )
123
- for edge in edges.values()
124
- if edge.tab_id == tab.id
125
- and edge.from_node_id in known_node_ids
126
- and edge.to_node_id in known_node_ids
127
- ]
128
- for node in tab_node_records:
129
- if node.position is None:
130
- continue
131
- tab.definition.view.positions[node.id] = node.position
132
- return cls(tabs=tabs, nodes=nodes, edges=edges, blueprints=blueprints)
133
-
134
-
135
- class WorkspaceStore:
136
- def __init__(self) -> None:
137
- self._lock = threading.Lock()
138
- self._snapshot: WorkspaceSnapshot | None = None
139
-
140
- def _load_snapshot(self) -> WorkspaceSnapshot:
141
- if self._snapshot is not None:
142
- return self._snapshot
143
- snapshot = self._load_snapshot_from_state_db()
144
- legacy_snapshot = self._load_snapshot_from_legacy_file()
145
- if self._snapshot_has_content(
146
- legacy_snapshot
147
- ) and not self._snapshot_has_content(snapshot):
148
- assert legacy_snapshot is not None
149
- snapshot = legacy_snapshot
150
- self._persist_snapshot(snapshot)
151
- if snapshot is None:
152
- snapshot = (
153
- legacy_snapshot if legacy_snapshot is not None else WorkspaceSnapshot()
154
- )
155
- self._snapshot = snapshot
156
- return snapshot
157
-
158
- def _load_snapshot_from_state_db(self) -> WorkspaceSnapshot | None:
159
- connection = open_state_db(create=False)
160
- if connection is None:
161
- return None
162
- try:
163
- raw: dict[str, object] = {
164
- "tabs": self._read_payload_rows(connection, "tabs"),
165
- "nodes": self._read_payload_rows(connection, "nodes"),
166
- "edges": self._read_payload_rows(connection, "edges"),
167
- "blueprints": self._read_payload_rows(connection, "blueprints"),
168
- }
169
- finally:
170
- connection.close()
171
- snapshot = WorkspaceSnapshot.from_mapping(raw)
172
- if snapshot.serialize() != raw:
173
- self._persist_snapshot(snapshot)
174
- return snapshot
175
-
176
- def _load_snapshot_from_legacy_file(self) -> WorkspaceSnapshot | None:
177
- workspace_file = get_legacy_workspace_file_path()
178
- if not workspace_file.exists():
179
- return None
180
- raw = json.loads(workspace_file.read_text(encoding="utf-8"))
181
- if not isinstance(raw, dict):
182
- return WorkspaceSnapshot()
183
- return WorkspaceSnapshot.from_mapping(raw)
184
-
185
- def _snapshot_has_content(self, snapshot: WorkspaceSnapshot | None) -> bool:
186
- return bool(
187
- snapshot is not None
188
- and (
189
- snapshot.tabs or snapshot.nodes or snapshot.edges or snapshot.blueprints
190
- )
191
- )
192
-
193
- def _read_payload_rows(
194
- self,
195
- connection,
196
- table_name: str,
197
- ) -> list[dict[str, object]]:
198
- try:
199
- rows = connection.execute(
200
- f"SELECT payload FROM {table_name} ORDER BY rowid"
201
- ).fetchall()
202
- except Exception as exc:
203
- raise RuntimeError(
204
- f"Failed to read workspace table `{table_name}` from state store: {exc}"
205
- ) from exc
206
- payloads: list[dict[str, object]] = []
207
- for row in rows:
208
- payload = row["payload"]
209
- if not isinstance(payload, str):
210
- continue
211
- parsed = json.loads(payload)
212
- if isinstance(parsed, dict):
213
- payloads.append(parsed)
214
- return payloads
215
-
216
- def _persist_snapshot(self, snapshot: WorkspaceSnapshot) -> None:
217
- connection = open_state_db(create=True)
218
- assert connection is not None
219
- try:
220
- with connection:
221
- connection.execute("DELETE FROM tabs")
222
- connection.execute("DELETE FROM nodes")
223
- connection.execute("DELETE FROM edges")
224
- connection.execute("DELETE FROM blueprints")
225
- connection.executemany(
226
- "INSERT INTO tabs (id, payload, updated_at) VALUES (?, ?, ?)",
227
- [
228
- (
229
- tab.id,
230
- json.dumps(tab.serialize(), ensure_ascii=False),
231
- tab.updated_at,
232
- )
233
- for tab in snapshot.tabs.values()
234
- ],
235
- )
236
- connection.executemany(
237
- """
238
- INSERT INTO nodes (id, payload, tab_id, node_type, updated_at)
239
- VALUES (?, ?, ?, ?, ?)
240
- """,
241
- [
242
- (
243
- record.id,
244
- json.dumps(record.serialize(), ensure_ascii=False),
245
- record.config.tab_id,
246
- record.config.node_type.value,
247
- record.updated_at,
248
- )
249
- for record in snapshot.nodes.values()
250
- ],
251
- )
252
- connection.executemany(
253
- "INSERT INTO edges (id, payload, tab_id) VALUES (?, ?, ?)",
254
- [
255
- (
256
- edge.id,
257
- json.dumps(edge.serialize(), ensure_ascii=False),
258
- edge.tab_id,
259
- )
260
- for tab in snapshot.tabs.values()
261
- for edge in (
262
- GraphEdge(
263
- id=item.id,
264
- tab_id=tab.id,
265
- from_node_id=item.from_node_id,
266
- from_port_key=item.from_port_key,
267
- to_node_id=item.to_node_id,
268
- to_port_key=item.to_port_key,
269
- kind=item.kind,
270
- created_at=item.created_at,
271
- )
272
- for item in tab.definition.edges
273
- )
274
- ],
275
- )
276
- connection.executemany(
277
- "INSERT INTO blueprints (id, payload, updated_at) VALUES (?, ?, ?)",
278
- [
279
- (
280
- blueprint.id,
281
- json.dumps(blueprint.serialize(), ensure_ascii=False),
282
- blueprint.updated_at,
283
- )
284
- for blueprint in snapshot.blueprints.values()
285
- ],
286
- )
287
- finally:
288
- connection.close()
289
-
290
- def reset_cache(self) -> None:
291
- with self._lock:
292
- self._snapshot = None
293
-
294
- def list_tabs(self) -> list[Tab]:
295
- with self._lock:
296
- return list(self._load_snapshot().tabs.values())
297
-
298
- def get_tab(self, tab_id: str) -> Tab | None:
299
- with self._lock:
300
- return self._load_snapshot().tabs.get(tab_id)
301
-
302
- def upsert_tab(self, tab: Tab) -> None:
303
- with self._lock:
304
- snapshot = self._load_snapshot()
305
- tab.updated_at = time.time()
306
- snapshot.tabs[tab.id] = tab
307
- self._persist_snapshot(snapshot)
308
-
309
- def delete_tab(self, tab_id: str) -> None:
310
- with self._lock:
311
- snapshot = self._load_snapshot()
312
- snapshot.tabs.pop(tab_id, None)
313
- node_ids = [
314
- node_id
315
- for node_id, node in snapshot.nodes.items()
316
- if node.config.tab_id == tab_id
317
- ]
318
- for node_id in node_ids:
319
- snapshot.nodes.pop(node_id, None)
320
- edge_ids = [
321
- edge_id
322
- for edge_id, edge in snapshot.edges.items()
323
- if edge.tab_id == tab_id
324
- or edge.from_node_id in node_ids
325
- or edge.to_node_id in node_ids
326
- ]
327
- for edge_id in edge_ids:
328
- snapshot.edges.pop(edge_id, None)
329
- self._persist_snapshot(snapshot)
330
-
331
- def list_node_records(self, tab_id: str | None = None) -> list[GraphNodeRecord]:
332
- with self._lock:
333
- nodes = list(self._load_snapshot().nodes.values())
334
- if tab_id is None:
335
- return nodes
336
- return [node for node in nodes if node.config.tab_id == tab_id]
337
-
338
- def get_node_record(self, node_id: str) -> GraphNodeRecord | None:
339
- with self._lock:
340
- return self._load_snapshot().nodes.get(node_id)
341
-
342
- def upsert_node_record(self, record: GraphNodeRecord) -> None:
343
- with self._lock:
344
- snapshot = self._load_snapshot()
345
- record.updated_at = time.time()
346
- snapshot.nodes[record.id] = record
347
- if record.config.tab_id and record.config.tab_id in snapshot.tabs:
348
- snapshot.tabs[record.config.tab_id].updated_at = record.updated_at
349
- self._persist_snapshot(snapshot)
350
-
351
- def delete_node_record(self, node_id: str) -> None:
352
- with self._lock:
353
- snapshot = self._load_snapshot()
354
- record = snapshot.nodes.pop(node_id, None)
355
- if record is None:
356
- return
357
- edge_ids = [
358
- edge_id
359
- for edge_id, edge in snapshot.edges.items()
360
- if edge.from_node_id == node_id or edge.to_node_id == node_id
361
- ]
362
- for edge_id in edge_ids:
363
- snapshot.edges.pop(edge_id, None)
364
- if record.config.tab_id and record.config.tab_id in snapshot.tabs:
365
- snapshot.tabs[record.config.tab_id].updated_at = time.time()
366
- self._persist_snapshot(snapshot)
367
-
368
- def list_edges(self, tab_id: str | None = None) -> list[GraphEdge]:
369
- with self._lock:
370
- snapshot = self._load_snapshot()
371
- result: list[GraphEdge] = []
372
- for tab in snapshot.tabs.values():
373
- if tab_id is not None and tab.id != tab_id:
374
- continue
375
- result.extend(
376
- GraphEdge(
377
- id=edge.id,
378
- tab_id=tab.id,
379
- from_node_id=edge.from_node_id,
380
- from_port_key=edge.from_port_key,
381
- to_node_id=edge.to_node_id,
382
- to_port_key=edge.to_port_key,
383
- kind=edge.kind,
384
- created_at=edge.created_at,
385
- )
386
- for edge in tab.definition.edges
387
- )
388
- return result
389
-
390
- def get_edge(self, edge_id: str) -> GraphEdge | None:
391
- with self._lock:
392
- snapshot = self._load_snapshot()
393
- for tab in snapshot.tabs.values():
394
- edge = next(
395
- (item for item in tab.definition.edges if item.id == edge_id),
396
- None,
397
- )
398
- if edge is None:
399
- continue
400
- return GraphEdge(
401
- id=edge.id,
402
- tab_id=tab.id,
403
- from_node_id=edge.from_node_id,
404
- from_port_key=edge.from_port_key,
405
- to_node_id=edge.to_node_id,
406
- to_port_key=edge.to_port_key,
407
- kind=edge.kind,
408
- created_at=edge.created_at,
409
- )
410
- return None
411
-
412
- def upsert_edge(self, edge: GraphEdge) -> None:
413
- with self._lock:
414
- snapshot = self._load_snapshot()
415
- if edge.tab_id is None or edge.tab_id not in snapshot.tabs:
416
- return
417
- tab = snapshot.tabs[edge.tab_id]
418
- tab.definition.edges = [
419
- item for item in tab.definition.edges if item.id != edge.id
420
- ]
421
- tab.definition.edges.append(edge)
422
- tab.updated_at = time.time()
423
- self._persist_snapshot(snapshot)
424
-
425
- def delete_edge(self, edge_id: str) -> None:
426
- with self._lock:
427
- snapshot = self._load_snapshot()
428
- for tab in snapshot.tabs.values():
429
- original_size = len(tab.definition.edges)
430
- tab.definition.edges = [
431
- edge for edge in tab.definition.edges if edge.id != edge_id
432
- ]
433
- if len(tab.definition.edges) == original_size:
434
- continue
435
- tab.updated_at = time.time()
436
- break
437
- self._persist_snapshot(snapshot)
438
-
439
- def list_blueprints(self) -> list[AgentBlueprint]:
440
- with self._lock:
441
- return list(self._load_snapshot().blueprints.values())
442
-
443
- def get_blueprint(self, blueprint_id: str) -> AgentBlueprint | None:
444
- with self._lock:
445
- return self._load_snapshot().blueprints.get(blueprint_id)
446
-
447
- def upsert_blueprint(self, blueprint: AgentBlueprint) -> None:
448
- with self._lock:
449
- snapshot = self._load_snapshot()
450
- updated_at = time.time()
451
- blueprint.updated_at = updated_at
452
- if not blueprint.version_history:
453
- blueprint.version_history.append(
454
- BlueprintVersionSummary(
455
- version=blueprint.version,
456
- updated_at=updated_at,
457
- )
458
- )
459
- elif blueprint.version_history[-1].version == blueprint.version:
460
- blueprint.version_history[-1].updated_at = updated_at
461
- else:
462
- blueprint.version_history.append(
463
- BlueprintVersionSummary(
464
- version=blueprint.version,
465
- updated_at=updated_at,
466
- )
467
- )
468
- snapshot.blueprints[blueprint.id] = blueprint
469
- self._persist_snapshot(snapshot)
470
-
471
- def delete_blueprint(self, blueprint_id: str) -> None:
472
- with self._lock:
473
- snapshot = self._load_snapshot()
474
- if snapshot.blueprints.pop(blueprint_id, None) is None:
475
- return
476
- self._persist_snapshot(snapshot)
477
-
478
-
479
- workspace_store = WorkspaceStore()
File without changes
@@ -1,6 +0,0 @@
1
- import os
2
- import tempfile
3
-
4
- if not os.environ.get("FLOWENT_APP_DATA_DIR"):
5
- _APP_DATA_DIR = tempfile.TemporaryDirectory(prefix="flowent-pytest-")
6
- os.environ["FLOWENT_APP_DATA_DIR"] = _APP_DATA_DIR.name
@@ -1,29 +0,0 @@
1
- import pytest
2
- from fastapi.testclient import TestClient
3
-
4
-
5
- @pytest.fixture
6
- def client(monkeypatch, tmp_path):
7
- import flowent.settings as settings_module
8
- from flowent.access import set_access_code
9
-
10
- settings_file = tmp_path / "settings.json"
11
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
12
- monkeypatch.setattr(settings_module, "_cached_settings", None)
13
-
14
- settings = settings_module.Settings()
15
- set_access_code(settings, "TEST-ACCESS-CODE")
16
- settings_module.save_settings(settings)
17
- monkeypatch.setattr(settings_module, "_cached_settings", None)
18
-
19
- from flowent.main import app
20
-
21
- with TestClient(app) as client:
22
- login_response = client.post(
23
- "/api/access/login",
24
- json={"code": "TEST-ACCESS-CODE"},
25
- )
26
- assert login_response.status_code == 200
27
- yield client
28
-
29
- monkeypatch.setattr(settings_module, "_cached_settings", None)