flowent 0.0.7 → 0.0.11

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 (387) 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/__init__.py +6 -2
  5. package/backend/src/flowent/__pycache__/__init__.cpython-313.pyc +0 -0
  6. package/backend/src/flowent/__pycache__/agent.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 +376 -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 +477 -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__/cli.cpython-313.pyc +0 -0
  59. package/backend/src/flowent/__pycache__/config.cpython-313.pyc +0 -0
  60. package/backend/src/flowent/__pycache__/events.cpython-313.pyc +0 -0
  61. package/backend/src/flowent/__pycache__/graph_runtime.cpython-313.pyc +0 -0
  62. package/backend/src/flowent/__pycache__/graph_service.cpython-313.pyc +0 -0
  63. package/backend/src/flowent/__pycache__/image_assets.cpython-313.pyc +0 -0
  64. package/backend/src/flowent/__pycache__/model_metadata.cpython-313.pyc +0 -0
  65. package/backend/src/flowent/__pycache__/network.cpython-313.pyc +0 -0
  66. package/backend/src/flowent/__pycache__/observability_service.cpython-313.pyc +0 -0
  67. package/backend/src/flowent/__pycache__/registry.cpython-313.pyc +0 -0
  68. package/backend/src/flowent/__pycache__/role_management.cpython-313.pyc +0 -0
  69. package/backend/src/flowent/__pycache__/runtime.cpython-313.pyc +0 -0
  70. package/backend/src/flowent/__pycache__/security.cpython-313.pyc +0 -0
  71. package/backend/src/flowent/__pycache__/settings.cpython-313.pyc +0 -0
  72. package/backend/src/flowent/__pycache__/settings_management.cpython-313.pyc +0 -0
  73. package/backend/src/flowent/__pycache__/state_db.cpython-313.pyc +0 -0
  74. package/backend/src/flowent/__pycache__/workspace_store.cpython-313.pyc +0 -0
  75. package/backend/src/flowent/access.py +0 -247
  76. package/backend/src/flowent/assistant_commands.py +0 -115
  77. package/backend/src/flowent/channels/__init__.py +0 -3
  78. package/backend/src/flowent/channels/__pycache__/__init__.cpython-313.pyc +0 -0
  79. package/backend/src/flowent/channels/__pycache__/telegram.cpython-313.pyc +0 -0
  80. package/backend/src/flowent/channels/telegram.py +0 -615
  81. package/backend/src/flowent/config.py +0 -14
  82. package/backend/src/flowent/dev.py +0 -3
  83. package/backend/src/flowent/events.py +0 -157
  84. package/backend/src/flowent/graph_runtime.py +0 -60
  85. package/backend/src/flowent/graph_service.py +0 -2401
  86. package/backend/src/flowent/image_assets.py +0 -356
  87. package/backend/src/flowent/model_metadata.py +0 -102
  88. package/backend/src/flowent/models/__init__.py +0 -125
  89. package/backend/src/flowent/models/__pycache__/__init__.cpython-313.pyc +0 -0
  90. package/backend/src/flowent/models/__pycache__/agent.cpython-313.pyc +0 -0
  91. package/backend/src/flowent/models/__pycache__/base.cpython-313.pyc +0 -0
  92. package/backend/src/flowent/models/__pycache__/blueprint.cpython-313.pyc +0 -0
  93. package/backend/src/flowent/models/__pycache__/content.cpython-313.pyc +0 -0
  94. package/backend/src/flowent/models/__pycache__/delta.cpython-313.pyc +0 -0
  95. package/backend/src/flowent/models/__pycache__/event.cpython-313.pyc +0 -0
  96. package/backend/src/flowent/models/__pycache__/graph.cpython-313.pyc +0 -0
  97. package/backend/src/flowent/models/__pycache__/history.cpython-313.pyc +0 -0
  98. package/backend/src/flowent/models/__pycache__/llm.cpython-313.pyc +0 -0
  99. package/backend/src/flowent/models/__pycache__/message.cpython-313.pyc +0 -0
  100. package/backend/src/flowent/models/__pycache__/tab.cpython-313.pyc +0 -0
  101. package/backend/src/flowent/models/__pycache__/todo.cpython-313.pyc +0 -0
  102. package/backend/src/flowent/models/agent.py +0 -34
  103. package/backend/src/flowent/models/base.py +0 -24
  104. package/backend/src/flowent/models/blueprint.py +0 -176
  105. package/backend/src/flowent/models/content.py +0 -164
  106. package/backend/src/flowent/models/delta.py +0 -44
  107. package/backend/src/flowent/models/event.py +0 -51
  108. package/backend/src/flowent/models/graph.py +0 -472
  109. package/backend/src/flowent/models/history.py +0 -272
  110. package/backend/src/flowent/models/llm.py +0 -62
  111. package/backend/src/flowent/models/message.py +0 -33
  112. package/backend/src/flowent/models/tab.py +0 -85
  113. package/backend/src/flowent/models/todo.py +0 -10
  114. package/backend/src/flowent/network.py +0 -146
  115. package/backend/src/flowent/observability_service.py +0 -218
  116. package/backend/src/flowent/prompts/__init__.py +0 -67
  117. package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  118. package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
  119. package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
  120. package/backend/src/flowent/prompts/common.py +0 -250
  121. package/backend/src/flowent/prompts/steward.py +0 -64
  122. package/backend/src/flowent/providers/__init__.py +0 -23
  123. package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  124. package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
  125. package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
  126. package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
  127. package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
  128. package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
  129. package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
  130. package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
  131. package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
  132. package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
  133. package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
  134. package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
  135. package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
  136. package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
  137. package/backend/src/flowent/providers/anthropic.py +0 -468
  138. package/backend/src/flowent/providers/base_url.py +0 -60
  139. package/backend/src/flowent/providers/configuration.py +0 -189
  140. package/backend/src/flowent/providers/content.py +0 -122
  141. package/backend/src/flowent/providers/errors.py +0 -223
  142. package/backend/src/flowent/providers/gateway.py +0 -169
  143. package/backend/src/flowent/providers/gemini.py +0 -447
  144. package/backend/src/flowent/providers/headers.py +0 -20
  145. package/backend/src/flowent/providers/management.py +0 -96
  146. package/backend/src/flowent/providers/ollama.py +0 -293
  147. package/backend/src/flowent/providers/openai.py +0 -422
  148. package/backend/src/flowent/providers/openai_responses.py +0 -655
  149. package/backend/src/flowent/providers/registry.py +0 -144
  150. package/backend/src/flowent/providers/sse.py +0 -31
  151. package/backend/src/flowent/providers/thinking.py +0 -79
  152. package/backend/src/flowent/registry.py +0 -73
  153. package/backend/src/flowent/role_management.py +0 -270
  154. package/backend/src/flowent/routes/__init__.py +0 -26
  155. package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
  156. package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
  157. package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
  158. package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
  159. package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
  160. package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
  161. package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
  162. package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
  163. package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
  164. package/backend/src/flowent/routes/__pycache__/settings.cpython-313.pyc +0 -0
  165. package/backend/src/flowent/routes/__pycache__/tabs.cpython-313.pyc +0 -0
  166. package/backend/src/flowent/routes/__pycache__/ws.cpython-313.pyc +0 -0
  167. package/backend/src/flowent/routes/access.py +0 -48
  168. package/backend/src/flowent/routes/assistant.py +0 -158
  169. package/backend/src/flowent/routes/image_assets.py +0 -33
  170. package/backend/src/flowent/routes/meta.py +0 -28
  171. package/backend/src/flowent/routes/nodes.py +0 -423
  172. package/backend/src/flowent/routes/prompts.py +0 -46
  173. package/backend/src/flowent/routes/providers_route.py +0 -365
  174. package/backend/src/flowent/routes/roles.py +0 -207
  175. package/backend/src/flowent/routes/settings.py +0 -379
  176. package/backend/src/flowent/routes/tabs.py +0 -298
  177. package/backend/src/flowent/routes/ws.py +0 -33
  178. package/backend/src/flowent/runtime.py +0 -160
  179. package/backend/src/flowent/security.py +0 -37
  180. package/backend/src/flowent/settings.py +0 -2112
  181. package/backend/src/flowent/settings_management.py +0 -394
  182. package/backend/src/flowent/state_db.py +0 -108
  183. package/backend/src/flowent/static/assets/AssistantPage-BW7XAd9I.js +0 -1
  184. package/backend/src/flowent/static/assets/ChannelsPage-tCJHgt6m.js +0 -1
  185. package/backend/src/flowent/static/assets/PageScaffold-f6g2l7XN.js +0 -1
  186. package/backend/src/flowent/static/assets/PromptsPage-C3Sxn2D7.js +0 -1
  187. package/backend/src/flowent/static/assets/ProvidersPage-BfmdXmNt.js +0 -3
  188. package/backend/src/flowent/static/assets/RolesPage-DET8wO4r.js +0 -1
  189. package/backend/src/flowent/static/assets/SettingsPage-D-g3deMm.js +0 -3
  190. package/backend/src/flowent/static/assets/ToolsPage-CDmtE2g4.js +0 -1
  191. package/backend/src/flowent/static/assets/WorkspacePage-AZsJ0sD0.js +0 -3
  192. package/backend/src/flowent/static/assets/WorkspacePanels-CteCjolX.js +0 -1
  193. package/backend/src/flowent/static/assets/alert-dialog-Duorp_S-.js +0 -1
  194. package/backend/src/flowent/static/assets/dialog-C3ixjGjN.js +0 -1
  195. package/backend/src/flowent/static/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  196. package/backend/src/flowent/static/assets/graph-vendor-CHpVij2M.css +0 -1
  197. package/backend/src/flowent/static/assets/graph-vendor-DRq_-6fV.js +0 -7
  198. package/backend/src/flowent/static/assets/index--o_0fv0N.css +0 -1
  199. package/backend/src/flowent/static/assets/index-C9HuekJm.js +0 -10
  200. package/backend/src/flowent/static/assets/layout.worker-jMHqAFbP.js +0 -24
  201. package/backend/src/flowent/static/assets/markdown-vendor-C9RtvaJh.js +0 -29
  202. package/backend/src/flowent/static/assets/modelParams-DmnF2hwR.js +0 -1
  203. package/backend/src/flowent/static/assets/providerTypes-DT3Ahwl_.js +0 -1
  204. package/backend/src/flowent/static/assets/react-vendor-mEs_JJxa.js +0 -9
  205. package/backend/src/flowent/static/assets/roles-CuRT_chR.js +0 -1
  206. package/backend/src/flowent/static/assets/rolldown-runtime-BYbx6iT9.js +0 -1
  207. package/backend/src/flowent/static/assets/select-DCfeNu-F.js +0 -1
  208. package/backend/src/flowent/static/assets/surface-pWwG5ogx.js +0 -1
  209. package/backend/src/flowent/static/assets/ui-vendor-C5pJa8N7.js +0 -51
  210. package/backend/src/flowent/static/assets/useAppRoute-FgSHBKhV.js +0 -1
  211. package/backend/src/flowent/static/favicon.svg +0 -4
  212. package/backend/src/flowent/tools/__init__.py +0 -176
  213. package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  214. package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
  215. package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
  216. package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
  217. package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
  218. package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
  219. package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
  220. package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
  221. package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
  222. package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
  223. package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
  224. package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
  225. package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
  226. package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
  227. package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
  228. package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
  229. package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
  230. package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
  231. package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
  232. package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
  233. package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
  234. package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
  235. package/backend/src/flowent/tools/connect.py +0 -100
  236. package/backend/src/flowent/tools/contacts.py +0 -22
  237. package/backend/src/flowent/tools/create_agent.py +0 -191
  238. package/backend/src/flowent/tools/create_tab.py +0 -61
  239. package/backend/src/flowent/tools/delete_tab.py +0 -39
  240. package/backend/src/flowent/tools/edit.py +0 -142
  241. package/backend/src/flowent/tools/exec.py +0 -118
  242. package/backend/src/flowent/tools/fetch.py +0 -85
  243. package/backend/src/flowent/tools/idle.py +0 -27
  244. package/backend/src/flowent/tools/list_roles.py +0 -68
  245. package/backend/src/flowent/tools/list_tabs.py +0 -100
  246. package/backend/src/flowent/tools/list_tools.py +0 -28
  247. package/backend/src/flowent/tools/manage_prompts.py +0 -102
  248. package/backend/src/flowent/tools/manage_providers.py +0 -220
  249. package/backend/src/flowent/tools/manage_roles.py +0 -275
  250. package/backend/src/flowent/tools/manage_settings.py +0 -326
  251. package/backend/src/flowent/tools/read.py +0 -152
  252. package/backend/src/flowent/tools/send.py +0 -68
  253. package/backend/src/flowent/tools/set_permissions.py +0 -99
  254. package/backend/src/flowent/tools/sleep.py +0 -41
  255. package/backend/src/flowent/tools/todo.py +0 -51
  256. package/backend/src/flowent/workspace_store.py +0 -479
  257. package/backend/tests/__init__.py +0 -0
  258. package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  259. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  260. package/backend/tests/conftest.py +0 -6
  261. package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  262. package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
  263. package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
  264. package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
  265. package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
  266. package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
  267. package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
  268. package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
  269. package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
  270. package/backend/tests/integration/api/conftest.py +0 -29
  271. package/backend/tests/integration/api/test_access_api.py +0 -182
  272. package/backend/tests/integration/api/test_assistant_api.py +0 -422
  273. package/backend/tests/integration/api/test_frontend_mounting.py +0 -61
  274. package/backend/tests/integration/api/test_meta_api.py +0 -32
  275. package/backend/tests/integration/api/test_nodes_api.py +0 -787
  276. package/backend/tests/integration/api/test_prompts_api.py +0 -47
  277. package/backend/tests/integration/api/test_roles_api.py +0 -228
  278. package/backend/tests/integration/api/test_tabs_api.py +0 -688
  279. package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
  280. package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  281. package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  282. package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
  283. package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
  284. package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
  285. package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
  286. package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  287. package/backend/tests/unit/agent/test_agent_public_api.py +0 -822
  288. package/backend/tests/unit/agent/test_agent_runtime.py +0 -3088
  289. package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
  290. package/backend/tests/unit/channels/test_telegram_channel.py +0 -552
  291. package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  292. package/backend/tests/unit/logging/test_logging.py +0 -132
  293. package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
  294. package/backend/tests/unit/prompts/test_prompts.py +0 -570
  295. package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  296. package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
  297. package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
  298. package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  299. package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
  300. package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
  301. package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
  302. package/backend/tests/unit/providers/test_anthropic_provider.py +0 -185
  303. package/backend/tests/unit/providers/test_errors.py +0 -68
  304. package/backend/tests/unit/providers/test_extract_delta_parts.py +0 -22
  305. package/backend/tests/unit/providers/test_openai_provider.py +0 -139
  306. package/backend/tests/unit/providers/test_openai_responses.py +0 -402
  307. package/backend/tests/unit/providers/test_provider_gateway.py +0 -359
  308. package/backend/tests/unit/providers/test_think_tag_parser.py +0 -36
  309. package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  310. package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
  311. package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  312. package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  313. package/backend/tests/unit/routes/test_prompts_routes.py +0 -82
  314. package/backend/tests/unit/routes/test_providers_route.py +0 -370
  315. package/backend/tests/unit/routes/test_roles_routes.py +0 -539
  316. package/backend/tests/unit/routes/test_settings_routes.py +0 -1123
  317. package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  318. package/backend/tests/unit/runtime/test_bootstrap_runtime.py +0 -1002
  319. package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  320. package/backend/tests/unit/sandbox/test_sandbox_tools.py +0 -78
  321. package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
  322. package/backend/tests/unit/security/test_security.py +0 -124
  323. package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
  324. package/backend/tests/unit/settings/test_settings_roles.py +0 -703
  325. package/backend/tests/unit/test_access.py +0 -45
  326. package/backend/tests/unit/test_cli.py +0 -102
  327. package/backend/tests/unit/test_graph_runtime.py +0 -72
  328. package/backend/tests/unit/test_network.py +0 -51
  329. package/backend/tests/unit/test_state_sqlite_storage.py +0 -87
  330. package/backend/tests/unit/test_workspace_store.py +0 -228
  331. package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  332. package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  333. package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  334. package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  335. package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  336. package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  337. package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  338. package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  339. package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  340. package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  341. package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  342. package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  343. package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  344. package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
  345. package/backend/tests/unit/tools/test_connect_tool.py +0 -228
  346. package/backend/tests/unit/tools/test_create_agent_tool.py +0 -404
  347. package/backend/tests/unit/tools/test_delete_tab_tool.py +0 -116
  348. package/backend/tests/unit/tools/test_edit_tool.py +0 -115
  349. package/backend/tests/unit/tools/test_exec_tool.py +0 -81
  350. package/backend/tests/unit/tools/test_fetch_tool.py +0 -65
  351. package/backend/tests/unit/tools/test_manage_prompts_tool.py +0 -92
  352. package/backend/tests/unit/tools/test_manage_providers_tool.py +0 -460
  353. package/backend/tests/unit/tools/test_manage_roles_tool.py +0 -411
  354. package/backend/tests/unit/tools/test_manage_settings_tool.py +0 -611
  355. package/backend/tests/unit/tools/test_read_tool.py +0 -33
  356. package/backend/tests/unit/tools/test_set_permissions_tool.py +0 -595
  357. package/backend/tests/unit/tools/test_todo_tool.py +0 -37
  358. package/backend/tests/unit/tools/test_tool_registry.py +0 -199
  359. package/dist/frontend/assets/AssistantPage-BW7XAd9I.js +0 -1
  360. package/dist/frontend/assets/ChannelsPage-tCJHgt6m.js +0 -1
  361. package/dist/frontend/assets/PageScaffold-f6g2l7XN.js +0 -1
  362. package/dist/frontend/assets/PromptsPage-C3Sxn2D7.js +0 -1
  363. package/dist/frontend/assets/ProvidersPage-BfmdXmNt.js +0 -3
  364. package/dist/frontend/assets/RolesPage-DET8wO4r.js +0 -1
  365. package/dist/frontend/assets/SettingsPage-D-g3deMm.js +0 -3
  366. package/dist/frontend/assets/ToolsPage-CDmtE2g4.js +0 -1
  367. package/dist/frontend/assets/WorkspacePage-AZsJ0sD0.js +0 -3
  368. package/dist/frontend/assets/WorkspacePanels-CteCjolX.js +0 -1
  369. package/dist/frontend/assets/alert-dialog-Duorp_S-.js +0 -1
  370. package/dist/frontend/assets/dialog-C3ixjGjN.js +0 -1
  371. package/dist/frontend/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  372. package/dist/frontend/assets/graph-vendor-CHpVij2M.css +0 -1
  373. package/dist/frontend/assets/graph-vendor-DRq_-6fV.js +0 -7
  374. package/dist/frontend/assets/index--o_0fv0N.css +0 -1
  375. package/dist/frontend/assets/index-C9HuekJm.js +0 -10
  376. package/dist/frontend/assets/layout.worker-jMHqAFbP.js +0 -24
  377. package/dist/frontend/assets/markdown-vendor-C9RtvaJh.js +0 -29
  378. package/dist/frontend/assets/modelParams-DmnF2hwR.js +0 -1
  379. package/dist/frontend/assets/providerTypes-DT3Ahwl_.js +0 -1
  380. package/dist/frontend/assets/react-vendor-mEs_JJxa.js +0 -9
  381. package/dist/frontend/assets/roles-CuRT_chR.js +0 -1
  382. package/dist/frontend/assets/rolldown-runtime-BYbx6iT9.js +0 -1
  383. package/dist/frontend/assets/select-DCfeNu-F.js +0 -1
  384. package/dist/frontend/assets/surface-pWwG5ogx.js +0 -1
  385. package/dist/frontend/assets/ui-vendor-C5pJa8N7.js +0 -51
  386. package/dist/frontend/assets/useAppRoute-FgSHBKhV.js +0 -1
  387. 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)