flowent 0.0.6 → 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 (398) hide show
  1. package/README.md +1 -4
  2. package/backend/README.md +1 -4
  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 +217 -3094
  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__/mcp_service.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 -2508
  86. package/backend/src/flowent/image_assets.py +0 -356
  87. package/backend/src/flowent/mcp_service.py +0 -1918
  88. package/backend/src/flowent/model_metadata.py +0 -102
  89. package/backend/src/flowent/models/__init__.py +0 -125
  90. package/backend/src/flowent/models/__pycache__/__init__.cpython-313.pyc +0 -0
  91. package/backend/src/flowent/models/__pycache__/agent.cpython-313.pyc +0 -0
  92. package/backend/src/flowent/models/__pycache__/base.cpython-313.pyc +0 -0
  93. package/backend/src/flowent/models/__pycache__/blueprint.cpython-313.pyc +0 -0
  94. package/backend/src/flowent/models/__pycache__/content.cpython-313.pyc +0 -0
  95. package/backend/src/flowent/models/__pycache__/delta.cpython-313.pyc +0 -0
  96. package/backend/src/flowent/models/__pycache__/event.cpython-313.pyc +0 -0
  97. package/backend/src/flowent/models/__pycache__/graph.cpython-313.pyc +0 -0
  98. package/backend/src/flowent/models/__pycache__/history.cpython-313.pyc +0 -0
  99. package/backend/src/flowent/models/__pycache__/llm.cpython-313.pyc +0 -0
  100. package/backend/src/flowent/models/__pycache__/message.cpython-313.pyc +0 -0
  101. package/backend/src/flowent/models/__pycache__/tab.cpython-313.pyc +0 -0
  102. package/backend/src/flowent/models/__pycache__/todo.cpython-313.pyc +0 -0
  103. package/backend/src/flowent/models/agent.py +0 -34
  104. package/backend/src/flowent/models/base.py +0 -24
  105. package/backend/src/flowent/models/blueprint.py +0 -176
  106. package/backend/src/flowent/models/content.py +0 -164
  107. package/backend/src/flowent/models/delta.py +0 -44
  108. package/backend/src/flowent/models/event.py +0 -51
  109. package/backend/src/flowent/models/graph.py +0 -472
  110. package/backend/src/flowent/models/history.py +0 -272
  111. package/backend/src/flowent/models/llm.py +0 -62
  112. package/backend/src/flowent/models/message.py +0 -33
  113. package/backend/src/flowent/models/tab.py +0 -85
  114. package/backend/src/flowent/models/todo.py +0 -10
  115. package/backend/src/flowent/network.py +0 -146
  116. package/backend/src/flowent/observability_service.py +0 -218
  117. package/backend/src/flowent/prompts/__init__.py +0 -67
  118. package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
  119. package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
  120. package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
  121. package/backend/src/flowent/prompts/common.py +0 -250
  122. package/backend/src/flowent/prompts/steward.py +0 -64
  123. package/backend/src/flowent/providers/__init__.py +0 -23
  124. package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  125. package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
  126. package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
  127. package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
  128. package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
  129. package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
  130. package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
  131. package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
  132. package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
  133. package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
  134. package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
  135. package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
  136. package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
  137. package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
  138. package/backend/src/flowent/providers/anthropic.py +0 -468
  139. package/backend/src/flowent/providers/base_url.py +0 -60
  140. package/backend/src/flowent/providers/configuration.py +0 -189
  141. package/backend/src/flowent/providers/content.py +0 -122
  142. package/backend/src/flowent/providers/errors.py +0 -223
  143. package/backend/src/flowent/providers/gateway.py +0 -169
  144. package/backend/src/flowent/providers/gemini.py +0 -447
  145. package/backend/src/flowent/providers/headers.py +0 -20
  146. package/backend/src/flowent/providers/management.py +0 -96
  147. package/backend/src/flowent/providers/ollama.py +0 -293
  148. package/backend/src/flowent/providers/openai.py +0 -422
  149. package/backend/src/flowent/providers/openai_responses.py +0 -655
  150. package/backend/src/flowent/providers/registry.py +0 -144
  151. package/backend/src/flowent/providers/sse.py +0 -31
  152. package/backend/src/flowent/providers/thinking.py +0 -79
  153. package/backend/src/flowent/registry.py +0 -73
  154. package/backend/src/flowent/role_management.py +0 -267
  155. package/backend/src/flowent/routes/__init__.py +0 -28
  156. package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
  157. package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
  158. package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
  159. package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
  160. package/backend/src/flowent/routes/__pycache__/mcp.cpython-313.pyc +0 -0
  161. package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
  162. package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
  163. package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
  164. package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
  165. package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
  166. package/backend/src/flowent/routes/__pycache__/settings.cpython-313.pyc +0 -0
  167. package/backend/src/flowent/routes/__pycache__/tabs.cpython-313.pyc +0 -0
  168. package/backend/src/flowent/routes/__pycache__/ws.cpython-313.pyc +0 -0
  169. package/backend/src/flowent/routes/access.py +0 -48
  170. package/backend/src/flowent/routes/assistant.py +0 -155
  171. package/backend/src/flowent/routes/image_assets.py +0 -33
  172. package/backend/src/flowent/routes/mcp.py +0 -125
  173. package/backend/src/flowent/routes/meta.py +0 -28
  174. package/backend/src/flowent/routes/nodes.py +0 -413
  175. package/backend/src/flowent/routes/prompts.py +0 -46
  176. package/backend/src/flowent/routes/providers_route.py +0 -365
  177. package/backend/src/flowent/routes/roles.py +0 -207
  178. package/backend/src/flowent/routes/settings.py +0 -328
  179. package/backend/src/flowent/routes/tabs.py +0 -310
  180. package/backend/src/flowent/routes/ws.py +0 -33
  181. package/backend/src/flowent/runtime.py +0 -165
  182. package/backend/src/flowent/security.py +0 -57
  183. package/backend/src/flowent/settings.py +0 -2518
  184. package/backend/src/flowent/settings_management.py +0 -298
  185. package/backend/src/flowent/state_db.py +0 -120
  186. package/backend/src/flowent/static/assets/AssistantPage-VBohhz4d.js +0 -1
  187. package/backend/src/flowent/static/assets/ChannelsPage-CIydPZA_.js +0 -1
  188. package/backend/src/flowent/static/assets/McpPage-CHPm2TPY.js +0 -7
  189. package/backend/src/flowent/static/assets/PageScaffold-DteOA8V7.js +0 -1
  190. package/backend/src/flowent/static/assets/PromptsPage-CSmJ3sZg.js +0 -1
  191. package/backend/src/flowent/static/assets/ProvidersPage-sl2jeG4e.js +0 -3
  192. package/backend/src/flowent/static/assets/RolesPage-DCe7W6Km.js +0 -1
  193. package/backend/src/flowent/static/assets/SettingsPage-Bix9e63E.js +0 -3
  194. package/backend/src/flowent/static/assets/ToolsPage-favNkj5C.js +0 -1
  195. package/backend/src/flowent/static/assets/WorkspaceCommandDialog-DRS6wiD6.js +0 -1
  196. package/backend/src/flowent/static/assets/WorkspacePage-KuaDjt_D.js +0 -3
  197. package/backend/src/flowent/static/assets/WorkspacePanels-BZxBw8M5.js +0 -1
  198. package/backend/src/flowent/static/assets/alert-dialog-DIBUCmqM.js +0 -1
  199. package/backend/src/flowent/static/assets/datetime-eJqd0V2S.js +0 -1
  200. package/backend/src/flowent/static/assets/dialog-BOvHIBrg.js +0 -1
  201. package/backend/src/flowent/static/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  202. package/backend/src/flowent/static/assets/graph-vendor-CHpVij2M.css +0 -1
  203. package/backend/src/flowent/static/assets/graph-vendor-DRq_-6fV.js +0 -7
  204. package/backend/src/flowent/static/assets/index-Biio-CoI.js +0 -10
  205. package/backend/src/flowent/static/assets/index-CmQvO7sl.css +0 -1
  206. package/backend/src/flowent/static/assets/layout.worker-jMHqAFbP.js +0 -24
  207. package/backend/src/flowent/static/assets/markdown-vendor-C9RtvaJh.js +0 -29
  208. package/backend/src/flowent/static/assets/modelParams-DcEhGnu0.js +0 -1
  209. package/backend/src/flowent/static/assets/react-vendor-mEs_JJxa.js +0 -9
  210. package/backend/src/flowent/static/assets/roles-BbIEIMeG.js +0 -1
  211. package/backend/src/flowent/static/assets/rolldown-runtime-BYbx6iT9.js +0 -1
  212. package/backend/src/flowent/static/assets/select-D9SwnlXF.js +0 -1
  213. package/backend/src/flowent/static/assets/surface-Bzr1FRG4.js +0 -1
  214. package/backend/src/flowent/static/assets/triState-DgLlKdRR.js +0 -1
  215. package/backend/src/flowent/static/assets/ui-vendor-UazN8rcv.js +0 -51
  216. package/backend/src/flowent/static/favicon.svg +0 -4
  217. package/backend/src/flowent/tools/__init__.py +0 -275
  218. package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  219. package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
  220. package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
  221. package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
  222. package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
  223. package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
  224. package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
  225. package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
  226. package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
  227. package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
  228. package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
  229. package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
  230. package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
  231. package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
  232. package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
  233. package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
  234. package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
  235. package/backend/src/flowent/tools/__pycache__/mcp.cpython-313.pyc +0 -0
  236. package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
  237. package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
  238. package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
  239. package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
  240. package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
  241. package/backend/src/flowent/tools/connect.py +0 -100
  242. package/backend/src/flowent/tools/contacts.py +0 -22
  243. package/backend/src/flowent/tools/create_agent.py +0 -191
  244. package/backend/src/flowent/tools/create_tab.py +0 -61
  245. package/backend/src/flowent/tools/delete_tab.py +0 -39
  246. package/backend/src/flowent/tools/edit.py +0 -142
  247. package/backend/src/flowent/tools/exec.py +0 -118
  248. package/backend/src/flowent/tools/fetch.py +0 -85
  249. package/backend/src/flowent/tools/idle.py +0 -27
  250. package/backend/src/flowent/tools/list_roles.py +0 -75
  251. package/backend/src/flowent/tools/list_tabs.py +0 -100
  252. package/backend/src/flowent/tools/list_tools.py +0 -28
  253. package/backend/src/flowent/tools/manage_prompts.py +0 -102
  254. package/backend/src/flowent/tools/manage_providers.py +0 -220
  255. package/backend/src/flowent/tools/manage_roles.py +0 -275
  256. package/backend/src/flowent/tools/manage_settings.py +0 -364
  257. package/backend/src/flowent/tools/mcp.py +0 -199
  258. package/backend/src/flowent/tools/read.py +0 -152
  259. package/backend/src/flowent/tools/send.py +0 -68
  260. package/backend/src/flowent/tools/set_permissions.py +0 -99
  261. package/backend/src/flowent/tools/sleep.py +0 -41
  262. package/backend/src/flowent/tools/todo.py +0 -51
  263. package/backend/src/flowent/workspace_store.py +0 -479
  264. package/backend/tests/__init__.py +0 -0
  265. package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
  266. package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  267. package/backend/tests/conftest.py +0 -6
  268. package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
  269. package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
  270. package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
  271. package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
  272. package/backend/tests/integration/api/__pycache__/test_mcp_api.cpython-313-pytest-9.0.3.pyc +0 -0
  273. package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
  274. package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
  275. package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
  276. package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
  277. package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
  278. package/backend/tests/integration/api/conftest.py +0 -29
  279. package/backend/tests/integration/api/test_access_api.py +0 -182
  280. package/backend/tests/integration/api/test_assistant_api.py +0 -354
  281. package/backend/tests/integration/api/test_frontend_mounting.py +0 -61
  282. package/backend/tests/integration/api/test_mcp_api.py +0 -116
  283. package/backend/tests/integration/api/test_meta_api.py +0 -33
  284. package/backend/tests/integration/api/test_nodes_api.py +0 -722
  285. package/backend/tests/integration/api/test_prompts_api.py +0 -47
  286. package/backend/tests/integration/api/test_roles_api.py +0 -228
  287. package/backend/tests/integration/api/test_tabs_api.py +0 -802
  288. package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
  289. package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
  290. package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  291. package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
  292. package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
  293. package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
  294. package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
  295. package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  296. package/backend/tests/unit/agent/test_agent_public_api.py +0 -837
  297. package/backend/tests/unit/agent/test_agent_runtime.py +0 -2942
  298. package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
  299. package/backend/tests/unit/channels/test_telegram_channel.py +0 -552
  300. package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
  301. package/backend/tests/unit/logging/test_logging.py +0 -132
  302. package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
  303. package/backend/tests/unit/prompts/test_prompts.py +0 -570
  304. package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  305. package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
  306. package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
  307. package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
  308. package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
  309. package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
  310. package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
  311. package/backend/tests/unit/providers/test_anthropic_provider.py +0 -185
  312. package/backend/tests/unit/providers/test_errors.py +0 -68
  313. package/backend/tests/unit/providers/test_extract_delta_parts.py +0 -22
  314. package/backend/tests/unit/providers/test_openai_provider.py +0 -139
  315. package/backend/tests/unit/providers/test_openai_responses.py +0 -402
  316. package/backend/tests/unit/providers/test_provider_gateway.py +0 -359
  317. package/backend/tests/unit/providers/test_think_tag_parser.py +0 -36
  318. package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  319. package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
  320. package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  321. package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
  322. package/backend/tests/unit/routes/test_prompts_routes.py +0 -104
  323. package/backend/tests/unit/routes/test_providers_route.py +0 -370
  324. package/backend/tests/unit/routes/test_roles_routes.py +0 -535
  325. package/backend/tests/unit/routes/test_settings_routes.py +0 -1142
  326. package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
  327. package/backend/tests/unit/runtime/test_bootstrap_runtime.py +0 -1002
  328. package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
  329. package/backend/tests/unit/sandbox/test_sandbox_tools.py +0 -78
  330. package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
  331. package/backend/tests/unit/security/test_security.py +0 -124
  332. package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
  333. package/backend/tests/unit/settings/test_settings_roles.py +0 -751
  334. package/backend/tests/unit/test_access.py +0 -45
  335. package/backend/tests/unit/test_cli.py +0 -124
  336. package/backend/tests/unit/test_graph_runtime.py +0 -72
  337. package/backend/tests/unit/test_network.py +0 -51
  338. package/backend/tests/unit/test_state_sqlite_storage.py +0 -159
  339. package/backend/tests/unit/test_workspace_store.py +0 -231
  340. package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  341. package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  342. package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  343. package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  344. package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  345. package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  346. package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  347. package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  348. package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  349. package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  350. package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  351. package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  352. package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
  353. package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
  354. package/backend/tests/unit/tools/test_connect_tool.py +0 -228
  355. package/backend/tests/unit/tools/test_create_agent_tool.py +0 -436
  356. package/backend/tests/unit/tools/test_delete_tab_tool.py +0 -116
  357. package/backend/tests/unit/tools/test_edit_tool.py +0 -115
  358. package/backend/tests/unit/tools/test_exec_tool.py +0 -81
  359. package/backend/tests/unit/tools/test_fetch_tool.py +0 -65
  360. package/backend/tests/unit/tools/test_manage_prompts_tool.py +0 -117
  361. package/backend/tests/unit/tools/test_manage_providers_tool.py +0 -460
  362. package/backend/tests/unit/tools/test_manage_roles_tool.py +0 -411
  363. package/backend/tests/unit/tools/test_manage_settings_tool.py +0 -611
  364. package/backend/tests/unit/tools/test_read_tool.py +0 -33
  365. package/backend/tests/unit/tools/test_set_permissions_tool.py +0 -595
  366. package/backend/tests/unit/tools/test_todo_tool.py +0 -37
  367. package/backend/tests/unit/tools/test_tool_registry.py +0 -194
  368. package/dist/frontend/assets/AssistantPage-VBohhz4d.js +0 -1
  369. package/dist/frontend/assets/ChannelsPage-CIydPZA_.js +0 -1
  370. package/dist/frontend/assets/McpPage-CHPm2TPY.js +0 -7
  371. package/dist/frontend/assets/PageScaffold-DteOA8V7.js +0 -1
  372. package/dist/frontend/assets/PromptsPage-CSmJ3sZg.js +0 -1
  373. package/dist/frontend/assets/ProvidersPage-sl2jeG4e.js +0 -3
  374. package/dist/frontend/assets/RolesPage-DCe7W6Km.js +0 -1
  375. package/dist/frontend/assets/SettingsPage-Bix9e63E.js +0 -3
  376. package/dist/frontend/assets/ToolsPage-favNkj5C.js +0 -1
  377. package/dist/frontend/assets/WorkspaceCommandDialog-DRS6wiD6.js +0 -1
  378. package/dist/frontend/assets/WorkspacePage-KuaDjt_D.js +0 -3
  379. package/dist/frontend/assets/WorkspacePanels-BZxBw8M5.js +0 -1
  380. package/dist/frontend/assets/alert-dialog-DIBUCmqM.js +0 -1
  381. package/dist/frontend/assets/datetime-eJqd0V2S.js +0 -1
  382. package/dist/frontend/assets/dialog-BOvHIBrg.js +0 -1
  383. package/dist/frontend/assets/elk-worker.min-C9JGDOE-.js +0 -6312
  384. package/dist/frontend/assets/graph-vendor-CHpVij2M.css +0 -1
  385. package/dist/frontend/assets/graph-vendor-DRq_-6fV.js +0 -7
  386. package/dist/frontend/assets/index-Biio-CoI.js +0 -10
  387. package/dist/frontend/assets/index-CmQvO7sl.css +0 -1
  388. package/dist/frontend/assets/layout.worker-jMHqAFbP.js +0 -24
  389. package/dist/frontend/assets/markdown-vendor-C9RtvaJh.js +0 -29
  390. package/dist/frontend/assets/modelParams-DcEhGnu0.js +0 -1
  391. package/dist/frontend/assets/react-vendor-mEs_JJxa.js +0 -9
  392. package/dist/frontend/assets/roles-BbIEIMeG.js +0 -1
  393. package/dist/frontend/assets/rolldown-runtime-BYbx6iT9.js +0 -1
  394. package/dist/frontend/assets/select-D9SwnlXF.js +0 -1
  395. package/dist/frontend/assets/surface-Bzr1FRG4.js +0 -1
  396. package/dist/frontend/assets/triState-DgLlKdRR.js +0 -1
  397. package/dist/frontend/assets/ui-vendor-UazN8rcv.js +0 -51
  398. package/dist/frontend/favicon.svg +0 -4
@@ -1,1002 +0,0 @@
1
- import json
2
- from uuid import UUID
3
-
4
- import pytest
5
-
6
- import flowent.settings as settings_module
7
- from flowent.agent import Agent
8
- from flowent.models import AgentState, AssistantText, ReceivedMessage
9
- from flowent.registry import registry
10
- from flowent.runtime import bootstrap_runtime, shutdown_runtime
11
- from flowent.settings import (
12
- CONDUCTOR_ROLE_DESCRIPTION,
13
- CONDUCTOR_ROLE_INCLUDED_TOOLS,
14
- CONDUCTOR_ROLE_NAME,
15
- CONDUCTOR_ROLE_SYSTEM_PROMPT,
16
- DESIGNER_ROLE_DESCRIPTION,
17
- DESIGNER_ROLE_INCLUDED_TOOLS,
18
- DESIGNER_ROLE_NAME,
19
- DESIGNER_ROLE_SYSTEM_PROMPT,
20
- STEWARD_ROLE_DESCRIPTION,
21
- STEWARD_ROLE_INCLUDED_TOOLS,
22
- STEWARD_ROLE_NAME,
23
- STEWARD_ROLE_SYSTEM_PROMPT,
24
- WORKER_ROLE_DESCRIPTION,
25
- WORKER_ROLE_INCLUDED_TOOLS,
26
- WORKER_ROLE_NAME,
27
- WORKER_ROLE_SYSTEM_PROMPT,
28
- RoleConfig,
29
- build_default_assistant_write_dirs,
30
- )
31
- from flowent.tools import MINIMUM_TOOLS
32
- from flowent.workspace_store import workspace_store
33
-
34
-
35
- def test_bootstrap_runtime_creates_only_assistant(
36
- monkeypatch,
37
- tmp_path,
38
- ):
39
- registry.reset()
40
- settings_file = tmp_path / "settings.json"
41
- settings_file.write_text(
42
- json.dumps(
43
- {
44
- "event_log": {"timestamp_format": "absolute"},
45
- "model": {"active_provider_id": "", "active_model": ""},
46
- "providers": [],
47
- "roles": [],
48
- }
49
- ),
50
- encoding="utf-8",
51
- )
52
-
53
- monkeypatch.setattr(Agent, "start", lambda self: None)
54
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
55
- monkeypatch.setattr(settings_module, "_cached_settings", None)
56
-
57
- bootstrap_runtime()
58
-
59
- try:
60
- nodes = registry.get_all()
61
- assistant = registry.get_assistant()
62
-
63
- assert len(nodes) == 1
64
- assert assistant is not None
65
- assert str(UUID(assistant.uuid)) == assistant.uuid
66
- assert assistant.config.node_type.value == "assistant"
67
- assert assistant.config.name == "Assistant"
68
- assert assistant.config.role_name == STEWARD_ROLE_NAME
69
- assert set(MINIMUM_TOOLS).issubset(set(assistant.config.tools))
70
- assert set(STEWARD_ROLE_INCLUDED_TOOLS).issubset(set(assistant.config.tools))
71
- assert assistant.config.write_dirs == build_default_assistant_write_dirs()
72
- assert assistant.config.allow_network is True
73
- finally:
74
- registry.reset()
75
-
76
-
77
- def test_bootstrap_runtime_restores_assistant_history(monkeypatch, tmp_path):
78
- settings_file = tmp_path / "settings.json"
79
- workspace_file = tmp_path / "workspace.json"
80
- assistant_id = "00000000-0000-0000-0000-000000000001"
81
- settings_file.write_text(
82
- json.dumps(
83
- {
84
- "event_log": {"timestamp_format": "absolute"},
85
- "model": {"active_provider_id": "", "active_model": ""},
86
- "providers": [],
87
- "roles": [],
88
- }
89
- ),
90
- encoding="utf-8",
91
- )
92
- workspace_file.write_text(
93
- json.dumps(
94
- {
95
- "tabs": [],
96
- "nodes": [
97
- {
98
- "id": assistant_id,
99
- "config": {
100
- "node_type": "assistant",
101
- "role_name": "Steward",
102
- "tab_id": None,
103
- "name": "Assistant",
104
- "tools": [],
105
- "write_dirs": [str(tmp_path)],
106
- "allow_network": True,
107
- },
108
- "state": "idle",
109
- "todos": [],
110
- "history": [
111
- {
112
- "type": "ReceivedMessage",
113
- "content": "hello",
114
- "from_id": "human",
115
- "timestamp": 1,
116
- },
117
- {
118
- "type": "AssistantText",
119
- "content": "hi there",
120
- "timestamp": 2,
121
- },
122
- ],
123
- "position": None,
124
- "created_at": 1,
125
- "updated_at": 1,
126
- }
127
- ],
128
- "edges": [],
129
- }
130
- ),
131
- encoding="utf-8",
132
- )
133
-
134
- monkeypatch.setattr(Agent, "start", lambda self: None)
135
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
136
- monkeypatch.setattr(settings_module, "_cached_settings", None)
137
-
138
- bootstrap_runtime()
139
-
140
- try:
141
- assistant = registry.get_assistant()
142
- assert assistant is not None
143
- assert assistant.uuid == assistant_id
144
- assert assistant.state == AgentState.IDLE
145
- assert any(
146
- isinstance(entry, ReceivedMessage) and entry.content == "hello"
147
- for entry in assistant.history
148
- )
149
- assert any(
150
- isinstance(entry, AssistantText) and entry.content == "hi there"
151
- for entry in assistant.history
152
- )
153
- finally:
154
- registry.reset()
155
-
156
-
157
- def _stop_all_agents(timeout: float = 1.0) -> None:
158
- for node in list(registry.get_all()):
159
- node.request_termination("test cleanup")
160
- for node in list(registry.get_all()):
161
- node.wait_for_termination(timeout=timeout)
162
- registry.reset()
163
-
164
-
165
- def test_bootstrap_runtime_creates_builtin_roles(
166
- monkeypatch,
167
- tmp_path,
168
- ):
169
- registry.reset()
170
- settings_file = tmp_path / "settings.json"
171
- settings_file.write_text(
172
- json.dumps(
173
- {
174
- "event_log": {"timestamp_format": "absolute"},
175
- "model": {"active_provider_id": "", "active_model": ""},
176
- "providers": [],
177
- "roles": [],
178
- }
179
- ),
180
- encoding="utf-8",
181
- )
182
-
183
- monkeypatch.setattr(Agent, "start", lambda self: None)
184
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
185
- monkeypatch.setattr(settings_module, "_cached_settings", None)
186
-
187
- bootstrap_runtime()
188
-
189
- try:
190
- settings = settings_module.get_settings()
191
-
192
- assert settings.roles == [
193
- RoleConfig(
194
- name=STEWARD_ROLE_NAME,
195
- description=STEWARD_ROLE_DESCRIPTION,
196
- system_prompt=STEWARD_ROLE_SYSTEM_PROMPT,
197
- included_tools=STEWARD_ROLE_INCLUDED_TOOLS,
198
- ),
199
- RoleConfig(
200
- name=WORKER_ROLE_NAME,
201
- description=WORKER_ROLE_DESCRIPTION,
202
- system_prompt=WORKER_ROLE_SYSTEM_PROMPT,
203
- included_tools=WORKER_ROLE_INCLUDED_TOOLS,
204
- ),
205
- RoleConfig(
206
- name=CONDUCTOR_ROLE_NAME,
207
- description=CONDUCTOR_ROLE_DESCRIPTION,
208
- system_prompt=CONDUCTOR_ROLE_SYSTEM_PROMPT,
209
- included_tools=CONDUCTOR_ROLE_INCLUDED_TOOLS,
210
- ),
211
- RoleConfig(
212
- name=DESIGNER_ROLE_NAME,
213
- description=DESIGNER_ROLE_DESCRIPTION,
214
- system_prompt=DESIGNER_ROLE_SYSTEM_PROMPT,
215
- included_tools=DESIGNER_ROLE_INCLUDED_TOOLS,
216
- ),
217
- ]
218
- finally:
219
- registry.reset()
220
-
221
-
222
- def test_bootstrap_runtime_reconciles_existing_builtin_roles(monkeypatch, tmp_path):
223
- registry.reset()
224
- settings_file = tmp_path / "settings.json"
225
- settings_file.write_text(
226
- json.dumps(
227
- {
228
- "event_log": {"timestamp_format": "absolute"},
229
- "model": {"active_provider_id": "", "active_model": ""},
230
- "providers": [],
231
- "roles": [
232
- {
233
- "name": WORKER_ROLE_NAME,
234
- "system_prompt": "Custom worker prompt.",
235
- "included_tools": [],
236
- "excluded_tools": ["fetch"],
237
- }
238
- ],
239
- }
240
- ),
241
- encoding="utf-8",
242
- )
243
-
244
- monkeypatch.setattr(Agent, "start", lambda self: None)
245
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
246
- monkeypatch.setattr(settings_module, "_cached_settings", None)
247
-
248
- bootstrap_runtime()
249
-
250
- try:
251
- settings = settings_module.get_settings()
252
-
253
- assert settings.roles == [
254
- RoleConfig(
255
- name=STEWARD_ROLE_NAME,
256
- description=STEWARD_ROLE_DESCRIPTION,
257
- system_prompt=STEWARD_ROLE_SYSTEM_PROMPT,
258
- included_tools=STEWARD_ROLE_INCLUDED_TOOLS,
259
- ),
260
- RoleConfig(
261
- name=WORKER_ROLE_NAME,
262
- description=WORKER_ROLE_DESCRIPTION,
263
- system_prompt=WORKER_ROLE_SYSTEM_PROMPT,
264
- included_tools=WORKER_ROLE_INCLUDED_TOOLS,
265
- ),
266
- RoleConfig(
267
- name=CONDUCTOR_ROLE_NAME,
268
- description=CONDUCTOR_ROLE_DESCRIPTION,
269
- system_prompt=CONDUCTOR_ROLE_SYSTEM_PROMPT,
270
- included_tools=CONDUCTOR_ROLE_INCLUDED_TOOLS,
271
- ),
272
- RoleConfig(
273
- name=DESIGNER_ROLE_NAME,
274
- description=DESIGNER_ROLE_DESCRIPTION,
275
- system_prompt=DESIGNER_ROLE_SYSTEM_PROMPT,
276
- included_tools=DESIGNER_ROLE_INCLUDED_TOOLS,
277
- ),
278
- ]
279
- finally:
280
- registry.reset()
281
-
282
-
283
- def test_bootstrap_runtime_uses_configured_assistant_role(monkeypatch, tmp_path):
284
- registry.reset()
285
- settings_file = tmp_path / "settings.json"
286
- settings_file.write_text(
287
- json.dumps(
288
- {
289
- "assistant": {"role_name": "Reviewer"},
290
- "event_log": {"timestamp_format": "absolute"},
291
- "model": {"active_provider_id": "", "active_model": ""},
292
- "providers": [],
293
- "roles": [
294
- {
295
- "name": "Reviewer",
296
- "system_prompt": "Review everything.",
297
- "included_tools": [],
298
- "excluded_tools": [],
299
- }
300
- ],
301
- }
302
- ),
303
- encoding="utf-8",
304
- )
305
-
306
- monkeypatch.setattr(Agent, "start", lambda self: None)
307
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
308
- monkeypatch.setattr(settings_module, "_cached_settings", None)
309
-
310
- bootstrap_runtime()
311
-
312
- try:
313
- assistant = registry.get_assistant()
314
- assert assistant is not None
315
- assert assistant.config.role_name == "Reviewer"
316
- assert settings_module.get_settings().assistant.role_name == "Reviewer"
317
- finally:
318
- registry.reset()
319
-
320
-
321
- def test_bootstrap_runtime_preserves_steward_tools_for_non_steward_assistant_role(
322
- monkeypatch,
323
- tmp_path,
324
- ):
325
- registry.reset()
326
- settings_file = tmp_path / "settings.json"
327
- settings_file.write_text(
328
- json.dumps(
329
- {
330
- "assistant": {"role_name": WORKER_ROLE_NAME},
331
- "event_log": {"timestamp_format": "absolute"},
332
- "model": {"active_provider_id": "", "active_model": ""},
333
- "providers": [],
334
- "roles": [],
335
- }
336
- ),
337
- encoding="utf-8",
338
- )
339
-
340
- monkeypatch.setattr(Agent, "start", lambda self: None)
341
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
342
- monkeypatch.setattr(settings_module, "_cached_settings", None)
343
-
344
- bootstrap_runtime()
345
-
346
- try:
347
- assistant = registry.get_assistant()
348
- assert assistant is not None
349
- assert assistant.config.role_name == WORKER_ROLE_NAME
350
- assert "create_workflow" in assistant.config.tools
351
- assert "delete_workflow" in assistant.config.tools
352
- assert "set_permissions" in assistant.config.tools
353
- assert "manage_settings" in assistant.config.tools
354
- assert "read" in assistant.config.tools
355
- assert "exec" in assistant.config.tools
356
- finally:
357
- registry.reset()
358
-
359
-
360
- def test_bootstrap_runtime_uses_configured_assistant_permissions(
361
- monkeypatch,
362
- tmp_path,
363
- ):
364
- registry.reset()
365
- allowed_dir = tmp_path / "assistant-write"
366
- settings_file = tmp_path / "settings.json"
367
- settings_file.write_text(
368
- json.dumps(
369
- {
370
- "assistant": {
371
- "role_name": "Reviewer",
372
- "allow_network": False,
373
- "write_dirs": [str(allowed_dir)],
374
- },
375
- "event_log": {"timestamp_format": "absolute"},
376
- "model": {"active_provider_id": "", "active_model": ""},
377
- "providers": [],
378
- "roles": [
379
- {
380
- "name": "Reviewer",
381
- "system_prompt": "Review everything.",
382
- "included_tools": [],
383
- "excluded_tools": [],
384
- }
385
- ],
386
- }
387
- ),
388
- encoding="utf-8",
389
- )
390
-
391
- monkeypatch.setattr(Agent, "start", lambda self: None)
392
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
393
- monkeypatch.setattr(settings_module, "_cached_settings", None)
394
-
395
- bootstrap_runtime()
396
-
397
- try:
398
- assistant = registry.get_assistant()
399
- assert assistant is not None
400
- assert assistant.config.allow_network is False
401
- assert assistant.config.write_dirs == [str(allowed_dir.resolve())]
402
- finally:
403
- registry.reset()
404
-
405
-
406
- def test_bootstrap_runtime_falls_back_to_steward_when_assistant_role_missing(
407
- monkeypatch,
408
- tmp_path,
409
- ):
410
- registry.reset()
411
- settings_file = tmp_path / "settings.json"
412
- settings_file.write_text(
413
- json.dumps(
414
- {
415
- "assistant": {"role_name": "Ghost"},
416
- "event_log": {"timestamp_format": "absolute"},
417
- "model": {"active_provider_id": "", "active_model": ""},
418
- "providers": [],
419
- "roles": [],
420
- }
421
- ),
422
- encoding="utf-8",
423
- )
424
-
425
- monkeypatch.setattr(Agent, "start", lambda self: None)
426
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
427
- monkeypatch.setattr(settings_module, "_cached_settings", None)
428
-
429
- bootstrap_runtime()
430
-
431
- try:
432
- assistant = registry.get_assistant()
433
- assert assistant is not None
434
- assert assistant.config.role_name == STEWARD_ROLE_NAME
435
- assert settings_module.get_settings().assistant.role_name == STEWARD_ROLE_NAME
436
- finally:
437
- registry.reset()
438
-
439
-
440
- def test_bootstrap_runtime_backfills_state_history_for_restored_nodes(
441
- monkeypatch,
442
- tmp_path,
443
- ):
444
- registry.reset()
445
- settings_file = tmp_path / "settings.json"
446
- workspace_file = tmp_path / "workspace.json"
447
- settings_file.write_text(
448
- json.dumps(
449
- {
450
- "event_log": {"timestamp_format": "absolute"},
451
- "model": {"active_provider_id": "", "active_model": ""},
452
- "providers": [],
453
- "roles": [],
454
- }
455
- ),
456
- encoding="utf-8",
457
- )
458
- workspace_file.write_text(
459
- json.dumps(
460
- {
461
- "tabs": [
462
- {
463
- "id": "tab-1",
464
- "title": "Restore",
465
- "created_at": 1,
466
- "updated_at": 1,
467
- }
468
- ],
469
- "nodes": [
470
- {
471
- "id": "node-1",
472
- "config": {
473
- "node_type": "agent",
474
- "role_name": "Worker",
475
- "tab_id": "tab-1",
476
- "name": "Restored Worker",
477
- "tools": [],
478
- "write_dirs": [],
479
- "allow_network": False,
480
- },
481
- "state": "idle",
482
- "todos": [],
483
- "history": [],
484
- "position": None,
485
- "created_at": 1,
486
- "updated_at": 1,
487
- }
488
- ],
489
- "edges": [],
490
- }
491
- ),
492
- encoding="utf-8",
493
- )
494
-
495
- monkeypatch.setattr(Agent, "start", lambda self: None)
496
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
497
- monkeypatch.setattr(settings_module, "_cached_settings", None)
498
-
499
- bootstrap_runtime()
500
-
501
- try:
502
- restored = registry.get("node-1")
503
- assert restored is not None
504
- assert restored.state == AgentState.IDLE
505
- assert restored.history == []
506
- finally:
507
- registry.reset()
508
-
509
-
510
- @pytest.mark.parametrize("restored_state", ["running", "sleeping"])
511
- def test_bootstrap_runtime_restores_active_nodes_as_idle(
512
- monkeypatch,
513
- tmp_path,
514
- restored_state,
515
- ):
516
- settings_file = tmp_path / "settings.json"
517
- workspace_file = tmp_path / "workspace.json"
518
- registry.reset()
519
- settings_file.write_text(
520
- json.dumps(
521
- {
522
- "event_log": {"timestamp_format": "absolute"},
523
- "model": {"active_provider_id": "", "active_model": ""},
524
- "providers": [],
525
- "roles": [],
526
- }
527
- ),
528
- encoding="utf-8",
529
- )
530
- workspace_file.write_text(
531
- json.dumps(
532
- {
533
- "tabs": [
534
- {
535
- "id": "tab-1",
536
- "title": "Restore",
537
- "created_at": 1,
538
- "updated_at": 1,
539
- }
540
- ],
541
- "nodes": [
542
- {
543
- "id": "node-1",
544
- "config": {
545
- "node_type": "agent",
546
- "role_name": "Worker",
547
- "tab_id": "tab-1",
548
- "name": "Restored Worker",
549
- "tools": [],
550
- "write_dirs": [],
551
- "allow_network": False,
552
- },
553
- "state": restored_state,
554
- "todos": [{"text": "resume me"}],
555
- "history": [
556
- {
557
- "type": "StateEntry",
558
- "state": restored_state,
559
- "reason": "before restart",
560
- }
561
- ],
562
- "position": None,
563
- "created_at": 1,
564
- "updated_at": 1,
565
- }
566
- ],
567
- "edges": [],
568
- }
569
- ),
570
- encoding="utf-8",
571
- )
572
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
573
- monkeypatch.setattr(settings_module, "_cached_settings", None)
574
-
575
- bootstrap_runtime()
576
-
577
- try:
578
- restored = registry.get("node-1")
579
- assert restored is not None
580
- assert restored.wait_until_idle(timeout=1.0) is True
581
- assert restored.state == AgentState.IDLE
582
- assert restored.uuid == "node-1"
583
- assert [todo.text for todo in restored.todos] == ["resume me"]
584
- assert all(
585
- entry.__class__.__name__ != "StateEntry" for entry in restored.history
586
- )
587
- persisted = workspace_store.get_node_record("node-1")
588
- assert persisted is not None
589
- assert persisted.state == AgentState.IDLE
590
- finally:
591
- _stop_all_agents()
592
-
593
-
594
- def test_bootstrap_runtime_restores_workflow_definition_without_runtime_connections(
595
- monkeypatch,
596
- tmp_path,
597
- ):
598
- settings_file = tmp_path / "settings.json"
599
- workspace_file = tmp_path / "workspace.json"
600
- registry.reset()
601
- settings_file.write_text(
602
- json.dumps(
603
- {
604
- "event_log": {"timestamp_format": "absolute"},
605
- "model": {"active_provider_id": "", "active_model": ""},
606
- "providers": [],
607
- "roles": [],
608
- }
609
- ),
610
- encoding="utf-8",
611
- )
612
- workspace_file.write_text(
613
- json.dumps(
614
- {
615
- "tabs": [
616
- {
617
- "id": "tab-1",
618
- "title": "Restore",
619
- "leader_id": "leader-1",
620
- "created_at": 1,
621
- "updated_at": 1,
622
- }
623
- ],
624
- "nodes": [
625
- {
626
- "id": "leader-1",
627
- "config": {
628
- "node_type": "agent",
629
- "role_name": "Conductor",
630
- "tab_id": "tab-1",
631
- "name": "Leader",
632
- "tools": [],
633
- "write_dirs": [],
634
- "allow_network": False,
635
- },
636
- "state": "idle",
637
- "todos": [],
638
- "history": [],
639
- "position": None,
640
- "created_at": 1,
641
- "updated_at": 1,
642
- },
643
- {
644
- "id": "node-a",
645
- "config": {
646
- "node_type": "agent",
647
- "role_name": "Worker",
648
- "tab_id": "tab-1",
649
- "name": "Worker A",
650
- "tools": [],
651
- "write_dirs": [],
652
- "allow_network": False,
653
- },
654
- "state": "idle",
655
- "todos": [],
656
- "history": [],
657
- "position": None,
658
- "created_at": 1,
659
- "updated_at": 1,
660
- },
661
- {
662
- "id": "node-b",
663
- "config": {
664
- "node_type": "agent",
665
- "role_name": "Worker",
666
- "tab_id": "tab-1",
667
- "name": "Worker B",
668
- "tools": [],
669
- "write_dirs": [],
670
- "allow_network": False,
671
- },
672
- "state": "idle",
673
- "todos": [],
674
- "history": [],
675
- "position": None,
676
- "created_at": 1,
677
- "updated_at": 1,
678
- },
679
- ],
680
- "edges": [
681
- {
682
- "id": "edge-1",
683
- "tab_id": "tab-1",
684
- "from_node_id": "leader-1",
685
- "to_node_id": "node-a",
686
- },
687
- {
688
- "id": "edge-2",
689
- "tab_id": "tab-1",
690
- "from_node_id": "node-a",
691
- "to_node_id": "node-b",
692
- },
693
- {
694
- "id": "edge-3",
695
- "tab_id": "tab-1",
696
- "from_node_id": "node-b",
697
- "to_node_id": "node-a",
698
- },
699
- ],
700
- }
701
- ),
702
- encoding="utf-8",
703
- )
704
- monkeypatch.setattr(Agent, "start", lambda self: None)
705
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
706
- monkeypatch.setattr(settings_module, "_cached_settings", None)
707
-
708
- bootstrap_runtime()
709
-
710
- try:
711
- leader = registry.get("leader-1")
712
- left = registry.get("node-a")
713
- right = registry.get("node-b")
714
- restored_tab = workspace_store.get_tab("tab-1")
715
-
716
- assert leader is not None
717
- assert left is not None
718
- assert right is not None
719
- assert restored_tab is not None
720
- assert leader.get_connections_snapshot() == []
721
- assert left.get_connections_snapshot() == []
722
- assert right.get_connections_snapshot() == []
723
- assert {node.id for node in restored_tab.definition.nodes} == {
724
- "node-a",
725
- "node-b",
726
- }
727
- assert {
728
- (edge.from_node_id, edge.to_node_id)
729
- for edge in restored_tab.definition.edges
730
- } == {
731
- ("node-a", "node-b"),
732
- ("node-b", "node-a"),
733
- }
734
- finally:
735
- registry.reset()
736
-
737
-
738
- def test_bootstrap_runtime_preserves_error_state_for_restored_nodes(
739
- monkeypatch,
740
- tmp_path,
741
- ):
742
- settings_file = tmp_path / "settings.json"
743
- workspace_file = tmp_path / "workspace.json"
744
- registry.reset()
745
- settings_file.write_text(
746
- json.dumps(
747
- {
748
- "event_log": {"timestamp_format": "absolute"},
749
- "model": {"active_provider_id": "", "active_model": ""},
750
- "providers": [],
751
- "roles": [],
752
- }
753
- ),
754
- encoding="utf-8",
755
- )
756
- workspace_file.write_text(
757
- json.dumps(
758
- {
759
- "tabs": [
760
- {
761
- "id": "tab-1",
762
- "title": "Restore",
763
- "created_at": 1,
764
- "updated_at": 1,
765
- }
766
- ],
767
- "nodes": [
768
- {
769
- "id": "node-1",
770
- "config": {
771
- "node_type": "agent",
772
- "role_name": "Worker",
773
- "tab_id": "tab-1",
774
- "name": "Broken Worker",
775
- "tools": [],
776
- "write_dirs": [],
777
- "allow_network": False,
778
- },
779
- "state": "error",
780
- "todos": [],
781
- "history": [
782
- {
783
- "type": "StateEntry",
784
- "state": "error",
785
- "reason": "provider failure",
786
- }
787
- ],
788
- "position": None,
789
- "created_at": 1,
790
- "updated_at": 1,
791
- }
792
- ],
793
- "edges": [],
794
- }
795
- ),
796
- encoding="utf-8",
797
- )
798
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
799
- monkeypatch.setattr(settings_module, "_cached_settings", None)
800
-
801
- bootstrap_runtime()
802
-
803
- try:
804
- restored = registry.get("node-1")
805
- assert restored is not None
806
- assert restored.state == AgentState.ERROR
807
- assert restored.wait_until_idle(timeout=0.05) is False
808
- assert all(
809
- entry.__class__.__name__ != "StateEntry" for entry in restored.history
810
- )
811
- persisted = workspace_store.get_node_record("node-1")
812
- assert persisted is not None
813
- assert persisted.state == AgentState.ERROR
814
- finally:
815
- _stop_all_agents()
816
-
817
-
818
- def test_bootstrap_runtime_skips_terminated_restored_nodes(monkeypatch, tmp_path):
819
- settings_file = tmp_path / "settings.json"
820
- workspace_file = tmp_path / "workspace.json"
821
- registry.reset()
822
- settings_file.write_text(
823
- json.dumps(
824
- {
825
- "event_log": {"timestamp_format": "absolute"},
826
- "model": {"active_provider_id": "", "active_model": ""},
827
- "providers": [],
828
- "roles": [],
829
- }
830
- ),
831
- encoding="utf-8",
832
- )
833
- workspace_file.write_text(
834
- json.dumps(
835
- {
836
- "tabs": [
837
- {
838
- "id": "tab-1",
839
- "title": "Restore",
840
- "created_at": 1,
841
- "updated_at": 1,
842
- }
843
- ],
844
- "nodes": [
845
- {
846
- "id": "node-1",
847
- "config": {
848
- "node_type": "agent",
849
- "role_name": "Worker",
850
- "tab_id": "tab-1",
851
- "name": "Finished Worker",
852
- "tools": [],
853
- "write_dirs": [],
854
- "allow_network": False,
855
- },
856
- "state": "terminated",
857
- "todos": [],
858
- "history": [
859
- {
860
- "type": "StateEntry",
861
- "state": "terminated",
862
- "reason": "done",
863
- }
864
- ],
865
- "position": None,
866
- "created_at": 1,
867
- "updated_at": 1,
868
- }
869
- ],
870
- "edges": [],
871
- }
872
- ),
873
- encoding="utf-8",
874
- )
875
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
876
- monkeypatch.setattr(settings_module, "_cached_settings", None)
877
-
878
- bootstrap_runtime()
879
-
880
- try:
881
- assert registry.get("node-1") is None
882
- persisted = workspace_store.get_node_record("node-1")
883
- assert persisted is not None
884
- assert persisted.state == AgentState.TERMINATED
885
- finally:
886
- _stop_all_agents()
887
-
888
-
889
- def test_shutdown_runtime_keeps_persistent_workspace_nodes_unterminated(
890
- monkeypatch,
891
- tmp_path,
892
- ):
893
- settings_file = tmp_path / "settings.json"
894
- workspace_file = tmp_path / "workspace.json"
895
- registry.reset()
896
- settings_file.write_text(
897
- json.dumps(
898
- {
899
- "event_log": {"timestamp_format": "absolute"},
900
- "model": {"active_provider_id": "", "active_model": ""},
901
- "providers": [],
902
- "roles": [],
903
- }
904
- ),
905
- encoding="utf-8",
906
- )
907
- workspace_file.write_text(
908
- json.dumps(
909
- {
910
- "tabs": [
911
- {
912
- "id": "tab-1",
913
- "title": "Restore",
914
- "created_at": 1,
915
- "updated_at": 1,
916
- }
917
- ],
918
- "nodes": [
919
- {
920
- "id": "node-1",
921
- "config": {
922
- "node_type": "agent",
923
- "role_name": "Worker",
924
- "tab_id": "tab-1",
925
- "name": "Persistent Worker",
926
- "tools": [],
927
- "write_dirs": [],
928
- "allow_network": False,
929
- },
930
- "state": "idle",
931
- "todos": [],
932
- "history": [
933
- {
934
- "type": "StateEntry",
935
- "state": "idle",
936
- "reason": "restored",
937
- }
938
- ],
939
- "position": None,
940
- "created_at": 1,
941
- "updated_at": 1,
942
- }
943
- ],
944
- "edges": [],
945
- }
946
- ),
947
- encoding="utf-8",
948
- )
949
- monkeypatch.setattr(settings_module, "_SETTINGS_FILE", settings_file)
950
- monkeypatch.setattr(settings_module, "_cached_settings", None)
951
-
952
- bootstrap_runtime()
953
-
954
- try:
955
- assistant = registry.get_assistant()
956
- persistent = registry.get("node-1")
957
- assert assistant is not None
958
- assert persistent is not None
959
- assistant_id = assistant.uuid
960
- assistant._append_history(ReceivedMessage(content="hello", from_id="human"))
961
- assistant._append_history(AssistantText(content="hi there"))
962
-
963
- shutdown_runtime()
964
-
965
- assert assistant.wait_for_termination(timeout=1.0) is True
966
- assert persistent.wait_for_termination(timeout=1.0) is True
967
- assert registry.get_all() == []
968
- assert assistant.state == AgentState.IDLE
969
- assert persistent.state == AgentState.IDLE
970
- persisted_assistant = workspace_store.get_node_record(assistant_id)
971
- assert persisted_assistant is not None
972
- assert persisted_assistant.state == AgentState.IDLE
973
- assert any(
974
- isinstance(entry, ReceivedMessage) and entry.content == "hello"
975
- for entry in persisted_assistant.history
976
- )
977
- assert any(
978
- isinstance(entry, AssistantText) and entry.content == "hi there"
979
- for entry in persisted_assistant.history
980
- )
981
- persisted = workspace_store.get_node_record("node-1")
982
- assert persisted is not None
983
- assert persisted.state == AgentState.IDLE
984
- assert all(
985
- entry.__class__.__name__ != "StateEntry" for entry in persistent.history
986
- )
987
-
988
- bootstrap_runtime()
989
-
990
- restored_assistant = registry.get_assistant()
991
- assert restored_assistant is not None
992
- assert restored_assistant.uuid == assistant_id
993
- assert any(
994
- isinstance(entry, ReceivedMessage) and entry.content == "hello"
995
- for entry in restored_assistant.history
996
- )
997
- assert any(
998
- isinstance(entry, AssistantText) and entry.content == "hi there"
999
- for entry in restored_assistant.history
1000
- )
1001
- finally:
1002
- _stop_all_agents()