flowent 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/backend/README.md +74 -0
- package/backend/pyproject.toml +2 -1
- package/backend/src/flowent/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/_version.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/access.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/agent.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/assistant_commands.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/cli.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/config.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/events.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/graph_runtime.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/graph_service.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/image_assets.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/logging.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/main.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/mcp_service.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/model_metadata.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/network.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/{stats_service.cpython-313.pyc → observability_service.cpython-313.pyc} +0 -0
- package/backend/src/flowent/__pycache__/registry.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/role_management.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/runtime.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/security.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/settings.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/settings_management.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/state_db.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/workspace_store.cpython-313.pyc +0 -0
- package/backend/src/flowent/agent.py +364 -52
- package/backend/src/flowent/assistant_commands.py +31 -22
- package/backend/src/flowent/channels/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/channels/__pycache__/telegram.cpython-313.pyc +0 -0
- package/backend/src/flowent/channels/telegram.py +4 -4
- package/backend/src/flowent/graph_service.py +1307 -145
- package/backend/src/flowent/mcp_service.py +21 -7
- package/backend/src/flowent/model_metadata.py +4 -0
- package/backend/src/flowent/models/__init__.py +6 -2
- package/backend/src/flowent/models/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/agent.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/base.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/blueprint.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/content.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/delta.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/event.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/graph.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/history.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/llm.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/message.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/tab.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/__pycache__/todo.cpython-313.pyc +0 -0
- package/backend/src/flowent/models/agent.py +1 -0
- package/backend/src/flowent/models/graph.py +44 -9
- package/backend/src/flowent/models/history.py +73 -15
- package/backend/src/flowent/models/llm.py +1 -0
- package/backend/src/flowent/models/message.py +6 -0
- package/backend/src/flowent/models/tab.py +38 -1
- package/backend/src/flowent/{stats_service.py → observability_service.py} +4 -4
- package/backend/src/flowent/prompts/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/prompts/__pycache__/common.cpython-313.pyc +0 -0
- package/backend/src/flowent/prompts/__pycache__/steward.cpython-313.pyc +0 -0
- package/backend/src/flowent/prompts/common.py +2 -2
- package/backend/src/flowent/prompts/steward.py +2 -2
- package/backend/src/flowent/providers/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/anthropic.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/base_url.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/configuration.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/content.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/errors.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/gateway.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/headers.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/management.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/openai.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/openai_responses.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/registry.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/sse.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/__pycache__/thinking.cpython-313.pyc +0 -0
- package/backend/src/flowent/providers/configuration.py +7 -0
- package/backend/src/flowent/role_management.py +12 -0
- package/backend/src/flowent/routes/__init__.py +0 -2
- package/backend/src/flowent/routes/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/access.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/assistant.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/image_assets.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/mcp.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/meta.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/nodes.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/prompts.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/providers_route.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/roles.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/settings.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/tabs.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/__pycache__/ws.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/assistant.py +4 -4
- package/backend/src/flowent/routes/nodes.py +54 -6
- package/backend/src/flowent/routes/providers_route.py +1 -0
- package/backend/src/flowent/routes/roles.py +1 -1
- package/backend/src/flowent/routes/settings.py +4 -0
- package/backend/src/flowent/routes/tabs.py +29 -11
- package/backend/src/flowent/runtime.py +7 -30
- package/backend/src/flowent/security.py +23 -8
- package/backend/src/flowent/settings.py +56 -5
- package/backend/src/flowent/settings_management.py +12 -0
- package/backend/src/flowent/static/assets/AssistantPage-VBohhz4d.js +1 -0
- package/backend/src/flowent/static/assets/ChannelsPage-CIydPZA_.js +1 -0
- package/backend/src/flowent/static/assets/McpPage-CHPm2TPY.js +7 -0
- package/backend/src/flowent/static/assets/PageScaffold-DteOA8V7.js +1 -0
- package/backend/src/flowent/static/assets/PromptsPage-CSmJ3sZg.js +1 -0
- package/backend/src/flowent/static/assets/ProvidersPage-sl2jeG4e.js +3 -0
- package/backend/src/flowent/static/assets/RolesPage-DCe7W6Km.js +1 -0
- package/backend/src/flowent/static/assets/SettingsPage-Bix9e63E.js +3 -0
- package/backend/src/flowent/static/assets/ToolsPage-favNkj5C.js +1 -0
- package/backend/src/flowent/static/assets/WorkspaceCommandDialog-DRS6wiD6.js +1 -0
- package/backend/src/flowent/static/assets/WorkspacePage-KuaDjt_D.js +3 -0
- package/backend/src/flowent/static/assets/WorkspacePanels-BZxBw8M5.js +1 -0
- package/backend/src/flowent/static/assets/alert-dialog-DIBUCmqM.js +1 -0
- package/backend/src/flowent/static/assets/{dialog-BeGSweF6.js → dialog-BOvHIBrg.js} +1 -1
- package/backend/src/flowent/static/assets/index-Biio-CoI.js +10 -0
- package/backend/src/flowent/static/assets/index-CmQvO7sl.css +1 -0
- package/backend/src/flowent/static/assets/modelParams-DcEhGnu0.js +1 -0
- package/backend/src/flowent/static/assets/roles-BbIEIMeG.js +1 -0
- package/backend/src/flowent/static/assets/select-D9SwnlXF.js +1 -0
- package/backend/src/flowent/static/assets/surface-Bzr1FRG4.js +1 -0
- package/backend/src/flowent/static/assets/{ui-vendor-Dg9NNnWX.js → ui-vendor-UazN8rcv.js} +15 -15
- package/backend/src/flowent/static/index.html +3 -4
- package/backend/src/flowent/tools/__init__.py +76 -2
- package/backend/src/flowent/tools/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/connect.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/contacts.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/create_agent.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/create_tab.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/delete_tab.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/edit.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/exec.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/fetch.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/idle.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/list_roles.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/list_tabs.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/list_tools.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/manage_prompts.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/manage_providers.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/manage_roles.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/manage_settings.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/mcp.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/read.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/send.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/set_permissions.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/sleep.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/__pycache__/todo.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/connect.py +10 -66
- package/backend/src/flowent/tools/contacts.py +1 -1
- package/backend/src/flowent/tools/create_agent.py +9 -88
- package/backend/src/flowent/tools/create_tab.py +7 -5
- package/backend/src/flowent/tools/exec.py +3 -2
- package/backend/src/flowent/tools/list_roles.py +29 -4
- package/backend/src/flowent/tools/list_tabs.py +4 -0
- package/backend/src/flowent/tools/list_tools.py +5 -1
- package/backend/src/flowent/tools/manage_settings.py +18 -0
- package/backend/src/flowent/tools/send.py +21 -3
- package/backend/src/flowent/tools/set_permissions.py +21 -6
- package/backend/tests/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/tests/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/conftest.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_access_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_assistant_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_frontend_mounting.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_mcp_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_meta_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_nodes_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/test_assistant_api.py +1 -1
- package/backend/tests/integration/api/test_nodes_api.py +257 -21
- package/backend/tests/integration/api/test_roles_api.py +3 -2
- package/backend/tests/integration/api/test_tabs_api.py +312 -11
- package/backend/tests/unit/__pycache__/test_access.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/__pycache__/test_cli.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/__pycache__/test_graph_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/__pycache__/test_network.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/__pycache__/test_workspace_store.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/agent/test_agent_public_api.py +162 -71
- package/backend/tests/unit/agent/test_agent_runtime.py +285 -69
- package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/prompts/__pycache__/test_prompts.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/prompts/test_prompts.py +3 -2
- package/backend/tests/unit/providers/__pycache__/test_anthropic_provider.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/providers/__pycache__/test_errors.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/providers/__pycache__/test_extract_delta_parts.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/routes/test_providers_route.py +2 -0
- package/backend/tests/unit/routes/test_roles_routes.py +109 -0
- package/backend/tests/unit/routes/test_settings_routes.py +4 -0
- package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/runtime/test_bootstrap_runtime.py +8 -18
- package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/security/__pycache__/test_security.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/security/test_security.py +16 -2
- package/backend/tests/unit/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/settings/test_settings_roles.py +40 -0
- package/backend/tests/unit/test_state_sqlite_storage.py +67 -1
- package/backend/tests/unit/tools/__pycache__/test_connect_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_create_agent_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_delete_tab_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_edit_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_exec_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_fetch_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_manage_prompts_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_manage_providers_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_manage_roles_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_manage_settings_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_read_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_set_permissions_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_todo_tool.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/__pycache__/test_tool_registry.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/tools/test_connect_tool.py +2 -3
- package/backend/tests/unit/tools/test_create_agent_tool.py +9 -97
- package/backend/tests/unit/tools/test_delete_tab_tool.py +33 -0
- package/backend/tests/unit/tools/test_manage_providers_tool.py +2 -0
- package/backend/tests/unit/tools/test_manage_settings_tool.py +3 -0
- package/backend/tests/unit/tools/test_set_permissions_tool.py +216 -12
- package/backend/tests/unit/tools/test_tool_registry.py +103 -0
- package/backend/uv.lock +1 -1
- package/dist/frontend/assets/AssistantPage-VBohhz4d.js +1 -0
- package/dist/frontend/assets/ChannelsPage-CIydPZA_.js +1 -0
- package/dist/frontend/assets/McpPage-CHPm2TPY.js +7 -0
- package/dist/frontend/assets/PageScaffold-DteOA8V7.js +1 -0
- package/dist/frontend/assets/PromptsPage-CSmJ3sZg.js +1 -0
- package/dist/frontend/assets/ProvidersPage-sl2jeG4e.js +3 -0
- package/dist/frontend/assets/RolesPage-DCe7W6Km.js +1 -0
- package/dist/frontend/assets/SettingsPage-Bix9e63E.js +3 -0
- package/dist/frontend/assets/ToolsPage-favNkj5C.js +1 -0
- package/dist/frontend/assets/WorkspaceCommandDialog-DRS6wiD6.js +1 -0
- package/dist/frontend/assets/WorkspacePage-KuaDjt_D.js +3 -0
- package/dist/frontend/assets/WorkspacePanels-BZxBw8M5.js +1 -0
- package/dist/frontend/assets/alert-dialog-DIBUCmqM.js +1 -0
- package/dist/frontend/assets/{dialog-BeGSweF6.js → dialog-BOvHIBrg.js} +1 -1
- package/dist/frontend/assets/index-Biio-CoI.js +10 -0
- package/dist/frontend/assets/index-CmQvO7sl.css +1 -0
- package/dist/frontend/assets/modelParams-DcEhGnu0.js +1 -0
- package/dist/frontend/assets/roles-BbIEIMeG.js +1 -0
- package/dist/frontend/assets/select-D9SwnlXF.js +1 -0
- package/dist/frontend/assets/surface-Bzr1FRG4.js +1 -0
- package/dist/frontend/assets/{ui-vendor-Dg9NNnWX.js → ui-vendor-UazN8rcv.js} +15 -15
- package/dist/frontend/index.html +3 -4
- package/package.json +3 -3
- package/backend/src/flowent/routes/__pycache__/stats.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/stats.py +0 -229
- package/backend/src/flowent/static/assets/AssistantPage-B3Xc08AS.js +0 -1
- package/backend/src/flowent/static/assets/ChannelsPage-ByLd28xk.js +0 -1
- package/backend/src/flowent/static/assets/HomePage-C0hAx9_l.js +0 -3
- package/backend/src/flowent/static/assets/McpPage-DkrYLvBv.js +0 -7
- package/backend/src/flowent/static/assets/PageScaffold-D4jO9ooX.js +0 -1
- package/backend/src/flowent/static/assets/PromptsPage-DWA7rRJd.js +0 -1
- package/backend/src/flowent/static/assets/ProvidersPage-PUWT8seJ.js +0 -3
- package/backend/src/flowent/static/assets/RolesPage-CqcclGRw.js +0 -1
- package/backend/src/flowent/static/assets/SettingsPage-8tS2cJgX.js +0 -3
- package/backend/src/flowent/static/assets/StatsPage-BX9khYzu.js +0 -1
- package/backend/src/flowent/static/assets/ToolsPage-9Tl9FdeD.js +0 -1
- package/backend/src/flowent/static/assets/WorkspaceCommandDialog-CCXxjDL8.js +0 -1
- package/backend/src/flowent/static/assets/WorkspacePanels-aMdJ7ZH7.js +0 -1
- package/backend/src/flowent/static/assets/alert-dialog-kFYVQ7oX.js +0 -1
- package/backend/src/flowent/static/assets/badge-74-3jsCg.js +0 -1
- package/backend/src/flowent/static/assets/constants-XUzFf6i1.js +0 -1
- package/backend/src/flowent/static/assets/index-BHC1Vhy8.css +0 -1
- package/backend/src/flowent/static/assets/index-CL1ALZ3r.js +0 -10
- package/backend/src/flowent/static/assets/modelParams-CaHd0903.js +0 -1
- package/backend/src/flowent/static/assets/roles-2OLDeTc5.js +0 -1
- package/backend/src/flowent/static/assets/select-DL_LPeDj.js +0 -1
- package/backend/src/flowent/static/assets/shared-CMxbpLeQ.js +0 -1
- package/backend/tests/unit/routes/__pycache__/test_stats_routes.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/routes/test_stats_routes.py +0 -149
- package/dist/frontend/assets/AssistantPage-B3Xc08AS.js +0 -1
- package/dist/frontend/assets/ChannelsPage-ByLd28xk.js +0 -1
- package/dist/frontend/assets/HomePage-C0hAx9_l.js +0 -3
- package/dist/frontend/assets/McpPage-DkrYLvBv.js +0 -7
- package/dist/frontend/assets/PageScaffold-D4jO9ooX.js +0 -1
- package/dist/frontend/assets/PromptsPage-DWA7rRJd.js +0 -1
- package/dist/frontend/assets/ProvidersPage-PUWT8seJ.js +0 -3
- package/dist/frontend/assets/RolesPage-CqcclGRw.js +0 -1
- package/dist/frontend/assets/SettingsPage-8tS2cJgX.js +0 -3
- package/dist/frontend/assets/StatsPage-BX9khYzu.js +0 -1
- package/dist/frontend/assets/ToolsPage-9Tl9FdeD.js +0 -1
- package/dist/frontend/assets/WorkspaceCommandDialog-CCXxjDL8.js +0 -1
- package/dist/frontend/assets/WorkspacePanels-aMdJ7ZH7.js +0 -1
- package/dist/frontend/assets/alert-dialog-kFYVQ7oX.js +0 -1
- package/dist/frontend/assets/badge-74-3jsCg.js +0 -1
- package/dist/frontend/assets/constants-XUzFf6i1.js +0 -1
- package/dist/frontend/assets/index-BHC1Vhy8.css +0 -1
- package/dist/frontend/assets/index-CL1ALZ3r.js +0 -10
- package/dist/frontend/assets/modelParams-CaHd0903.js +0 -1
- package/dist/frontend/assets/roles-2OLDeTc5.js +0 -1
- package/dist/frontend/assets/select-DL_LPeDj.js +0 -1
- package/dist/frontend/assets/shared-CMxbpLeQ.js +0 -1
- /package/backend/src/flowent/static/assets/{datetime-m6_O_Ci9.js → datetime-eJqd0V2S.js} +0 -0
- /package/backend/src/flowent/static/assets/{markdown-vendor-DVdy_w12.js → markdown-vendor-C9RtvaJh.js} +0 -0
- /package/backend/src/flowent/static/assets/{triState-DEr3NkXV.js → triState-DgLlKdRR.js} +0 -0
- /package/dist/frontend/assets/{datetime-m6_O_Ci9.js → datetime-eJqd0V2S.js} +0 -0
- /package/dist/frontend/assets/{markdown-vendor-DVdy_w12.js → markdown-vendor-C9RtvaJh.js} +0 -0
- /package/dist/frontend/assets/{triState-DEr3NkXV.js → triState-DgLlKdRR.js} +0 -0
|
@@ -12,6 +12,7 @@ from flowent.settings import (
|
|
|
12
12
|
build_model_context_window_tokens,
|
|
13
13
|
build_model_input_image,
|
|
14
14
|
build_model_output_image,
|
|
15
|
+
build_model_structured_output,
|
|
15
16
|
build_provider_headers,
|
|
16
17
|
build_provider_retry_429_delay_seconds,
|
|
17
18
|
serialize_provider_model_catalog_entry,
|
|
@@ -27,6 +28,7 @@ class ProviderModelCatalogPayload(Protocol):
|
|
|
27
28
|
context_window_tokens: int | None
|
|
28
29
|
input_image: bool | None
|
|
29
30
|
output_image: bool | None
|
|
31
|
+
structured_output: bool | None
|
|
30
32
|
|
|
31
33
|
|
|
32
34
|
def validate_provider_base_url_input(
|
|
@@ -72,6 +74,10 @@ def build_provider_model_catalog_entry(
|
|
|
72
74
|
payload.output_image,
|
|
73
75
|
field_name=f"{field_name_prefix}.output_image",
|
|
74
76
|
),
|
|
77
|
+
structured_output=build_model_structured_output(
|
|
78
|
+
payload.structured_output,
|
|
79
|
+
field_name=f"{field_name_prefix}.structured_output",
|
|
80
|
+
),
|
|
75
81
|
)
|
|
76
82
|
|
|
77
83
|
|
|
@@ -178,5 +184,6 @@ def serialize_discovered_model_catalog_entry(model: ModelInfo) -> dict[str, obje
|
|
|
178
184
|
context_window_tokens=model.context_window_tokens,
|
|
179
185
|
input_image=model.capabilities.input_image,
|
|
180
186
|
output_image=model.capabilities.output_image,
|
|
187
|
+
structured_output=model.capabilities.structured_output,
|
|
181
188
|
)
|
|
182
189
|
)
|
|
@@ -67,6 +67,11 @@ def resolve_role_tool_config(
|
|
|
67
67
|
included_tools: list[str] | None,
|
|
68
68
|
excluded_tools: list[str] | None,
|
|
69
69
|
) -> tuple[list[str], list[str]]:
|
|
70
|
+
from flowent.tools import (
|
|
71
|
+
is_assistant_only_mcp_tool_name,
|
|
72
|
+
is_assistant_only_tool_name,
|
|
73
|
+
)
|
|
74
|
+
|
|
70
75
|
next_included = normalize_tool_names(
|
|
71
76
|
included_tools
|
|
72
77
|
if included_tools is not None
|
|
@@ -74,6 +79,13 @@ def resolve_role_tool_config(
|
|
|
74
79
|
if current
|
|
75
80
|
else []
|
|
76
81
|
)
|
|
82
|
+
if included_tools is not None:
|
|
83
|
+
next_included = [
|
|
84
|
+
tool_name
|
|
85
|
+
for tool_name in next_included
|
|
86
|
+
if not is_assistant_only_tool_name(tool_name)
|
|
87
|
+
and not is_assistant_only_mcp_tool_name(tool_name)
|
|
88
|
+
]
|
|
77
89
|
next_excluded = normalize_tool_names(
|
|
78
90
|
excluded_tools
|
|
79
91
|
if excluded_tools is not None
|
|
@@ -10,7 +10,6 @@ from flowent.routes.prompts import router as prompts_router
|
|
|
10
10
|
from flowent.routes.providers_route import router as providers_router
|
|
11
11
|
from flowent.routes.roles import router as roles_router
|
|
12
12
|
from flowent.routes.settings import router as settings_router
|
|
13
|
-
from flowent.routes.stats import router as stats_router
|
|
14
13
|
from flowent.routes.tabs import router as tabs_router
|
|
15
14
|
from flowent.routes.ws import router as ws_router
|
|
16
15
|
|
|
@@ -24,7 +23,6 @@ router.include_router(roles_router)
|
|
|
24
23
|
router.include_router(providers_router)
|
|
25
24
|
router.include_router(prompts_router)
|
|
26
25
|
router.include_router(settings_router)
|
|
27
|
-
router.include_router(stats_router)
|
|
28
26
|
router.include_router(tabs_router)
|
|
29
27
|
router.include_router(meta_router)
|
|
30
28
|
router.include_router(ws_router)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -7,8 +7,8 @@ from fastapi import APIRouter, HTTPException
|
|
|
7
7
|
from pydantic import BaseModel
|
|
8
8
|
|
|
9
9
|
from flowent.assistant_commands import (
|
|
10
|
-
|
|
11
|
-
|
|
10
|
+
ConversationCommandError,
|
|
11
|
+
execute_conversation_command_input,
|
|
12
12
|
)
|
|
13
13
|
from flowent.image_assets import require_image_asset
|
|
14
14
|
from flowent.models import (
|
|
@@ -110,11 +110,11 @@ async def send_assistant_message(req: AssistantMessageRequest) -> dict:
|
|
|
110
110
|
|
|
111
111
|
try:
|
|
112
112
|
executed_command = (
|
|
113
|
-
|
|
113
|
+
execute_conversation_command_input(assistant, command_input)
|
|
114
114
|
if isinstance(command_input, str)
|
|
115
115
|
else None
|
|
116
116
|
)
|
|
117
|
-
except
|
|
117
|
+
except ConversationCommandError as exc:
|
|
118
118
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
119
119
|
except (RuntimeError, TimeoutError, LLMProviderError) as exc:
|
|
120
120
|
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
@@ -5,7 +5,17 @@ from typing import Literal
|
|
|
5
5
|
from fastapi import APIRouter, HTTPException
|
|
6
6
|
from pydantic import BaseModel
|
|
7
7
|
|
|
8
|
-
from flowent.
|
|
8
|
+
from flowent.assistant_commands import (
|
|
9
|
+
ConversationCommandError,
|
|
10
|
+
execute_conversation_command_input,
|
|
11
|
+
)
|
|
12
|
+
from flowent.graph_service import (
|
|
13
|
+
is_tab_leader,
|
|
14
|
+
list_node_connection_ids,
|
|
15
|
+
resolve_effective_permissions_for_agent,
|
|
16
|
+
resolve_effective_permissions_for_node_record,
|
|
17
|
+
)
|
|
18
|
+
from flowent.providers.errors import LLMProviderError
|
|
9
19
|
from flowent.registry import registry
|
|
10
20
|
from flowent.settings import (
|
|
11
21
|
find_provider,
|
|
@@ -196,11 +206,15 @@ async def get_node(node_id: str) -> dict:
|
|
|
196
206
|
record_id = node.uuid
|
|
197
207
|
record_state = node.state
|
|
198
208
|
target_config = node.config
|
|
209
|
+
allow_network, write_dirs = resolve_effective_permissions_for_agent(node)
|
|
199
210
|
else:
|
|
200
211
|
assert record is not None
|
|
201
212
|
record_id = record.id
|
|
202
213
|
record_state = record.state
|
|
203
214
|
target_config = record.config
|
|
215
|
+
allow_network, write_dirs = resolve_effective_permissions_for_node_record(
|
|
216
|
+
record
|
|
217
|
+
)
|
|
204
218
|
history = (
|
|
205
219
|
node.get_history_snapshot()
|
|
206
220
|
if node is not None
|
|
@@ -219,7 +233,7 @@ async def get_node(node_id: str) -> dict:
|
|
|
219
233
|
"role_name": target_config.role_name,
|
|
220
234
|
"is_leader": is_tab_leader(node_id=record_id, tab_id=target_config.tab_id),
|
|
221
235
|
"state": record_state.value,
|
|
222
|
-
"contacts": node.
|
|
236
|
+
"contacts": node.get_contacts_info() if node is not None else [],
|
|
223
237
|
"connections": (
|
|
224
238
|
list_node_connection_ids(
|
|
225
239
|
tab_id=target_config.tab_id,
|
|
@@ -232,8 +246,12 @@ async def get_node(node_id: str) -> dict:
|
|
|
232
246
|
"todos": [t.serialize() for t in todos],
|
|
233
247
|
"capabilities": _serialize_model_capabilities(target_config.role_name),
|
|
234
248
|
"tools": sorted(set(target_config.tools) | set(MINIMUM_TOOLS)),
|
|
235
|
-
"write_dirs": list(
|
|
236
|
-
"allow_network":
|
|
249
|
+
"write_dirs": list(write_dirs),
|
|
250
|
+
"allow_network": allow_network,
|
|
251
|
+
"workflow_permissions": {
|
|
252
|
+
"allow_network": allow_network,
|
|
253
|
+
"write_dirs": list(write_dirs),
|
|
254
|
+
},
|
|
237
255
|
"position": record.position.serialize()
|
|
238
256
|
if record is not None and record.position is not None
|
|
239
257
|
else None,
|
|
@@ -304,8 +322,14 @@ async def clear_node_chat(node_id: str) -> dict:
|
|
|
304
322
|
node = registry.get(node_id)
|
|
305
323
|
if node is None:
|
|
306
324
|
raise HTTPException(status_code=404, detail="Node not found")
|
|
307
|
-
if node.config.node_type != NodeType.ASSISTANT
|
|
308
|
-
|
|
325
|
+
if node.config.node_type != NodeType.ASSISTANT and not is_tab_leader(
|
|
326
|
+
node_id=node.uuid,
|
|
327
|
+
tab_id=node.config.tab_id,
|
|
328
|
+
):
|
|
329
|
+
raise HTTPException(
|
|
330
|
+
status_code=400,
|
|
331
|
+
detail="Can only clear Assistant or workflow chats",
|
|
332
|
+
)
|
|
309
333
|
|
|
310
334
|
try:
|
|
311
335
|
node.clear_chat_history()
|
|
@@ -321,6 +345,7 @@ async def clear_node_chat(node_id: str) -> dict:
|
|
|
321
345
|
async def dispatch_node_message(node_id: str, req: DispatchNodeMessageRequest) -> dict:
|
|
322
346
|
from flowent.graph_service import dispatch_node_message
|
|
323
347
|
from flowent.models import NodeType, content_parts_to_text, has_image_parts
|
|
348
|
+
from flowent.models import TextPart as ModelTextPart
|
|
324
349
|
|
|
325
350
|
node = registry.get(node_id)
|
|
326
351
|
if node is None:
|
|
@@ -354,6 +379,29 @@ async def dispatch_node_message(node_id: str, req: DispatchNodeMessageRequest) -
|
|
|
354
379
|
detail="Current model does not support `input_image`.",
|
|
355
380
|
)
|
|
356
381
|
|
|
382
|
+
command_input = (
|
|
383
|
+
parts[0].text
|
|
384
|
+
if len(parts) == 1 and isinstance(parts[0], ModelTextPart)
|
|
385
|
+
else None
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
try:
|
|
389
|
+
executed_command = (
|
|
390
|
+
execute_conversation_command_input(node, command_input)
|
|
391
|
+
if isinstance(command_input, str)
|
|
392
|
+
else None
|
|
393
|
+
)
|
|
394
|
+
except ConversationCommandError as exc:
|
|
395
|
+
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
396
|
+
except (RuntimeError, TimeoutError, LLMProviderError) as exc:
|
|
397
|
+
raise HTTPException(status_code=409, detail=str(exc)) from exc
|
|
398
|
+
|
|
399
|
+
if executed_command is not None:
|
|
400
|
+
return {
|
|
401
|
+
"status": "command_executed",
|
|
402
|
+
"command_name": executed_command.command_name,
|
|
403
|
+
}
|
|
404
|
+
|
|
357
405
|
error, message_id = dispatch_node_message(
|
|
358
406
|
node_id=node_id,
|
|
359
407
|
content=content_parts_to_text(parts),
|
|
@@ -70,7 +70,7 @@ async def get_roles_bootstrap() -> dict[str, object]:
|
|
|
70
70
|
return {
|
|
71
71
|
"roles": [serialize_role(role) for role in settings.roles],
|
|
72
72
|
"providers": [serialize_provider(provider) for provider in settings.providers],
|
|
73
|
-
"tools": list_agent_visible_tool_descriptors(),
|
|
73
|
+
"tools": list_agent_visible_tool_descriptors(include_assistant_only=False),
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
|
|
@@ -138,6 +138,7 @@ async def update_settings(req: UpdateSettingsRequest) -> dict[str, object]:
|
|
|
138
138
|
context_window_tokens: object = MISSING
|
|
139
139
|
input_image: object = MISSING
|
|
140
140
|
output_image: object = MISSING
|
|
141
|
+
structured_output: object = MISSING
|
|
141
142
|
timeout_ms: object = MISSING
|
|
142
143
|
retry_policy: object = MISSING
|
|
143
144
|
max_retries: object = MISSING
|
|
@@ -159,6 +160,8 @@ async def update_settings(req: UpdateSettingsRequest) -> dict[str, object]:
|
|
|
159
160
|
input_image = req.model.get("input_image")
|
|
160
161
|
if "output_image" in req.model:
|
|
161
162
|
output_image = req.model.get("output_image")
|
|
163
|
+
if "structured_output" in req.model:
|
|
164
|
+
structured_output = req.model.get("structured_output")
|
|
162
165
|
if "timeout_ms" in req.model:
|
|
163
166
|
timeout_ms = req.model.get("timeout_ms")
|
|
164
167
|
if "retry_policy" in req.model:
|
|
@@ -189,6 +192,7 @@ async def update_settings(req: UpdateSettingsRequest) -> dict[str, object]:
|
|
|
189
192
|
context_window_tokens=context_window_tokens,
|
|
190
193
|
input_image=input_image,
|
|
191
194
|
output_image=output_image,
|
|
195
|
+
structured_output=structured_output,
|
|
192
196
|
max_retries=max_retries,
|
|
193
197
|
retry_policy=retry_policy,
|
|
194
198
|
timeout_ms=timeout_ms,
|
|
@@ -4,10 +4,12 @@ from fastapi import APIRouter, HTTPException
|
|
|
4
4
|
from pydantic import BaseModel, ConfigDict
|
|
5
5
|
|
|
6
6
|
from flowent.graph_service import (
|
|
7
|
+
activate_tab,
|
|
7
8
|
create_agent_node,
|
|
8
9
|
create_edge,
|
|
9
10
|
create_graph_node,
|
|
10
11
|
create_tab,
|
|
12
|
+
deactivate_tab,
|
|
11
13
|
delete_agent_node,
|
|
12
14
|
delete_edge,
|
|
13
15
|
delete_tab,
|
|
@@ -18,7 +20,7 @@ from flowent.graph_service import (
|
|
|
18
20
|
serialize_tab_summary,
|
|
19
21
|
update_tab_definition,
|
|
20
22
|
)
|
|
21
|
-
from flowent.models import AgentState,
|
|
23
|
+
from flowent.models import AgentState, WorkflowNodeKind
|
|
22
24
|
from flowent.registry import registry
|
|
23
25
|
from flowent.workspace_store import workspace_store
|
|
24
26
|
|
|
@@ -39,8 +41,6 @@ class CreateTabNodeRequest(BaseModel):
|
|
|
39
41
|
name: str | None = None
|
|
40
42
|
config: dict[str, object] = {}
|
|
41
43
|
tools: list[str] = []
|
|
42
|
-
write_dirs: list[str] = []
|
|
43
|
-
allow_network: bool = False
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class CreateTabEdgeRequest(BaseModel):
|
|
@@ -49,7 +49,7 @@ class CreateTabEdgeRequest(BaseModel):
|
|
|
49
49
|
from_port_key: str = "out"
|
|
50
50
|
to_node_id: str
|
|
51
51
|
to_port_key: str = "in"
|
|
52
|
-
kind: str =
|
|
52
|
+
kind: str | None = None
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
class UpdateTabDefinitionRequest(BaseModel):
|
|
@@ -136,6 +136,30 @@ async def duplicate_workflow_route(tab_id: str) -> dict[str, object]:
|
|
|
136
136
|
return serialize_tab_summary(duplicated)
|
|
137
137
|
|
|
138
138
|
|
|
139
|
+
@router.post("/api/workflows/{tab_id}/activate")
|
|
140
|
+
async def activate_workflow_route(tab_id: str) -> dict[str, object]:
|
|
141
|
+
updated, errors, error = activate_tab(tab_id=tab_id, actor_id=tab_id)
|
|
142
|
+
if errors:
|
|
143
|
+
raise HTTPException(status_code=400, detail={"errors": errors})
|
|
144
|
+
if error is not None or updated is None:
|
|
145
|
+
raise HTTPException(
|
|
146
|
+
status_code=404 if error and error.endswith("not found") else 400,
|
|
147
|
+
detail=error or "Failed to activate workflow",
|
|
148
|
+
)
|
|
149
|
+
return serialize_tab_summary(updated)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@router.post("/api/workflows/{tab_id}/deactivate")
|
|
153
|
+
async def deactivate_workflow_route(tab_id: str) -> dict[str, object]:
|
|
154
|
+
updated, error = deactivate_tab(tab_id=tab_id, actor_id=tab_id)
|
|
155
|
+
if error is not None or updated is None:
|
|
156
|
+
raise HTTPException(
|
|
157
|
+
status_code=404 if error and error.endswith("not found") else 400,
|
|
158
|
+
detail=error or "Failed to deactivate workflow",
|
|
159
|
+
)
|
|
160
|
+
return serialize_tab_summary(updated)
|
|
161
|
+
|
|
162
|
+
|
|
139
163
|
@router.get("/api/workflows/{tab_id}")
|
|
140
164
|
async def get_workflow(tab_id: str) -> dict[str, object]:
|
|
141
165
|
tab = workspace_store.get_tab(tab_id)
|
|
@@ -201,8 +225,6 @@ async def create_workflow_node(
|
|
|
201
225
|
tab_id=tab_id,
|
|
202
226
|
name=req.name,
|
|
203
227
|
tools=req.tools,
|
|
204
|
-
write_dirs=req.write_dirs,
|
|
205
|
-
allow_network=req.allow_network,
|
|
206
228
|
)
|
|
207
229
|
if error is not None or record is None:
|
|
208
230
|
raise HTTPException(
|
|
@@ -236,17 +258,13 @@ async def create_workflow_edge(
|
|
|
236
258
|
tab = workspace_store.get_tab(tab_id)
|
|
237
259
|
if tab is None:
|
|
238
260
|
raise HTTPException(status_code=404, detail="Workflow not found")
|
|
239
|
-
try:
|
|
240
|
-
edge_kind = EdgeKind(req.kind.strip())
|
|
241
|
-
except ValueError as exc:
|
|
242
|
-
raise HTTPException(status_code=400, detail="Invalid edge kind") from exc
|
|
243
261
|
edge, error = create_edge(
|
|
244
262
|
tab_id=tab_id,
|
|
245
263
|
from_node_id=req.from_node_id,
|
|
246
264
|
from_port_key=req.from_port_key,
|
|
247
265
|
to_node_id=req.to_node_id,
|
|
248
266
|
to_port_key=req.to_port_key,
|
|
249
|
-
kind=
|
|
267
|
+
kind=req.kind or "",
|
|
250
268
|
)
|
|
251
269
|
if error is not None or edge is None:
|
|
252
270
|
raise HTTPException(status_code=400, detail=error or "Failed to create edge")
|
|
@@ -48,9 +48,10 @@ def bootstrap_runtime() -> None:
|
|
|
48
48
|
from flowent.graph_service import (
|
|
49
49
|
build_assistant_tools,
|
|
50
50
|
ensure_tab_leaders,
|
|
51
|
+
resolve_effective_permissions_for_node_record,
|
|
51
52
|
)
|
|
52
53
|
from flowent.mcp_service import mcp_service
|
|
53
|
-
from flowent.models import AgentState, NodeConfig, NodeType
|
|
54
|
+
from flowent.models import AgentState, NodeConfig, NodeType
|
|
54
55
|
from flowent.settings import (
|
|
55
56
|
ensure_builtin_roles,
|
|
56
57
|
get_settings,
|
|
@@ -94,20 +95,6 @@ def bootstrap_runtime() -> None:
|
|
|
94
95
|
summary=assistant_record.execution_context_summary,
|
|
95
96
|
history_cutoff=assistant_record.execution_context_history_cutoff,
|
|
96
97
|
)
|
|
97
|
-
if not any(isinstance(entry, StateEntry) for entry in assistant.history):
|
|
98
|
-
assistant.history.insert(
|
|
99
|
-
0,
|
|
100
|
-
StateEntry(state=assistant_record.state.value, reason="restored"),
|
|
101
|
-
)
|
|
102
|
-
if assistant_record.state in {
|
|
103
|
-
AgentState.INITIALIZING,
|
|
104
|
-
AgentState.IDLE,
|
|
105
|
-
AgentState.RUNNING,
|
|
106
|
-
AgentState.SLEEPING,
|
|
107
|
-
}:
|
|
108
|
-
assistant.history.append(
|
|
109
|
-
StateEntry(state=AgentState.IDLE.value, reason="restored")
|
|
110
|
-
)
|
|
111
98
|
assistant.todos = list(assistant_record.todos)
|
|
112
99
|
assistant.prime_runtime_state(
|
|
113
100
|
AgentState.ERROR
|
|
@@ -126,6 +113,9 @@ def bootstrap_runtime() -> None:
|
|
|
126
113
|
continue
|
|
127
114
|
if record.state == AgentState.TERMINATED:
|
|
128
115
|
continue
|
|
116
|
+
allow_network, write_dirs = resolve_effective_permissions_for_node_record(
|
|
117
|
+
record
|
|
118
|
+
)
|
|
129
119
|
node = Agent(
|
|
130
120
|
NodeConfig(
|
|
131
121
|
node_type=record.config.node_type,
|
|
@@ -133,8 +123,8 @@ def bootstrap_runtime() -> None:
|
|
|
133
123
|
tab_id=record.config.tab_id,
|
|
134
124
|
name=record.config.name,
|
|
135
125
|
tools=list(record.config.tools),
|
|
136
|
-
write_dirs=
|
|
137
|
-
allow_network=
|
|
126
|
+
write_dirs=write_dirs,
|
|
127
|
+
allow_network=allow_network,
|
|
138
128
|
),
|
|
139
129
|
uuid=record.id,
|
|
140
130
|
)
|
|
@@ -143,19 +133,6 @@ def bootstrap_runtime() -> None:
|
|
|
143
133
|
summary=record.execution_context_summary,
|
|
144
134
|
history_cutoff=record.execution_context_history_cutoff,
|
|
145
135
|
)
|
|
146
|
-
if not any(isinstance(entry, StateEntry) for entry in node.history):
|
|
147
|
-
node.history.insert(
|
|
148
|
-
0,
|
|
149
|
-
StateEntry(state=record.state.value, reason="restored"),
|
|
150
|
-
)
|
|
151
|
-
if record.state in {
|
|
152
|
-
AgentState.INITIALIZING,
|
|
153
|
-
AgentState.RUNNING,
|
|
154
|
-
AgentState.SLEEPING,
|
|
155
|
-
}:
|
|
156
|
-
node.history.append(
|
|
157
|
-
StateEntry(state=AgentState.IDLE.value, reason="restored")
|
|
158
|
-
)
|
|
159
136
|
node.todos = list(record.todos)
|
|
160
137
|
node.prime_runtime_state(
|
|
161
138
|
AgentState.ERROR if record.state == AgentState.ERROR else AgentState.IDLE
|
|
@@ -9,6 +9,18 @@ if TYPE_CHECKING:
|
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
def authorize(tool_name: str, agent: Agent, args: dict[str, Any]) -> str | None:
|
|
12
|
+
from flowent.graph_service import resolve_effective_permissions_for_agent
|
|
13
|
+
from flowent.models import NodeType
|
|
14
|
+
from flowent.tools import (
|
|
15
|
+
is_assistant_only_mcp_tool_name,
|
|
16
|
+
is_assistant_only_tool_name,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
if agent.node_type != NodeType.ASSISTANT and is_assistant_only_tool_name(tool_name):
|
|
20
|
+
return "Ask the Assistant to manage workflows or settings"
|
|
21
|
+
|
|
22
|
+
allow_network, write_dirs = resolve_effective_permissions_for_agent(agent)
|
|
23
|
+
|
|
12
24
|
if tool_name.startswith("mcp__"):
|
|
13
25
|
from flowent.mcp_service import mcp_service
|
|
14
26
|
from flowent.settings import find_mcp_server, get_settings
|
|
@@ -16,27 +28,30 @@ def authorize(tool_name: str, agent: Agent, args: dict[str, Any]) -> str | None:
|
|
|
16
28
|
descriptor = mcp_service.get_dynamic_tool_descriptor(tool_name)
|
|
17
29
|
if descriptor is None:
|
|
18
30
|
return f"MCP tool not found: {tool_name}"
|
|
31
|
+
if agent.node_type != NodeType.ASSISTANT and is_assistant_only_mcp_tool_name(
|
|
32
|
+
descriptor.tool_name
|
|
33
|
+
):
|
|
34
|
+
return "Ask the Assistant to manage workflows or settings"
|
|
19
35
|
server = find_mcp_server(get_settings(), descriptor.server_name)
|
|
20
36
|
if (
|
|
21
37
|
server is not None
|
|
22
38
|
and server.transport == "streamable_http"
|
|
23
|
-
and not
|
|
39
|
+
and not allow_network
|
|
24
40
|
):
|
|
25
|
-
return "Network access is disabled for this
|
|
26
|
-
if descriptor.open_world_hint and not
|
|
27
|
-
return "Network access is disabled for this
|
|
41
|
+
return "Network access is disabled for this workflow"
|
|
42
|
+
if descriptor.open_world_hint and not allow_network:
|
|
43
|
+
return "Network access is disabled for this workflow"
|
|
28
44
|
return None
|
|
29
45
|
|
|
30
46
|
if tool_name == "edit":
|
|
31
|
-
write_dirs = agent.config.write_dirs
|
|
32
47
|
if not write_dirs:
|
|
33
|
-
return "Write access is disabled for this
|
|
48
|
+
return "Write access is disabled for this workflow"
|
|
34
49
|
path = args.get("path")
|
|
35
50
|
if isinstance(path, str) and not is_path_writable(path, write_dirs):
|
|
36
51
|
return f"Path not in write_dirs: {path}"
|
|
37
52
|
return None
|
|
38
53
|
|
|
39
|
-
if tool_name == "fetch" and not
|
|
40
|
-
return "Network access is disabled for this
|
|
54
|
+
if tool_name == "fetch" and not allow_network:
|
|
55
|
+
return "Network access is disabled for this workflow"
|
|
41
56
|
|
|
42
57
|
return None
|