flowent 0.0.4 → 0.0.6
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
|
@@ -444,13 +444,11 @@ def _build_root_uri(path: str) -> str:
|
|
|
444
444
|
|
|
445
445
|
|
|
446
446
|
def _build_roots_for_agent(agent: Agent) -> list[dict[str, str]]:
|
|
447
|
+
from flowent.graph_service import resolve_effective_permissions_for_agent
|
|
447
448
|
from flowent.settings import get_runtime_working_dir_path, resolve_path
|
|
448
449
|
|
|
449
450
|
workspace_root = str(get_runtime_working_dir_path())
|
|
450
|
-
|
|
451
|
-
boundary_dirs = list(get_settings().assistant.write_dirs)
|
|
452
|
-
else:
|
|
453
|
-
boundary_dirs = list(agent.config.write_dirs)
|
|
451
|
+
_, boundary_dirs = resolve_effective_permissions_for_agent(agent)
|
|
454
452
|
ordered_paths: list[str] = []
|
|
455
453
|
seen: set[str] = set()
|
|
456
454
|
for path in [workspace_root, *boundary_dirs]:
|
|
@@ -1577,12 +1575,17 @@ class MCPService:
|
|
|
1577
1575
|
return snapshot.serialize()
|
|
1578
1576
|
|
|
1579
1577
|
def _visible_server_names_for_agent(self, agent: Agent) -> list[str]:
|
|
1578
|
+
from flowent.graph_service import resolve_effective_permissions_for_agent
|
|
1579
|
+
|
|
1580
1580
|
settings = get_settings()
|
|
1581
|
+
allow_network, _ = resolve_effective_permissions_for_agent(agent)
|
|
1581
1582
|
visible_names: list[str] = []
|
|
1582
1583
|
seen: set[str] = set()
|
|
1583
1584
|
for server in settings.mcp_servers:
|
|
1584
1585
|
if server.name in seen or not server.enabled:
|
|
1585
1586
|
continue
|
|
1587
|
+
if server.transport == "streamable_http" and not allow_network:
|
|
1588
|
+
continue
|
|
1586
1589
|
snapshot = self._get_snapshot(server.name)
|
|
1587
1590
|
if snapshot is None or snapshot.status != "connected":
|
|
1588
1591
|
continue
|
|
@@ -1622,9 +1625,17 @@ class MCPService:
|
|
|
1622
1625
|
return None
|
|
1623
1626
|
|
|
1624
1627
|
def list_agent_dynamic_tools(self, agent: Agent) -> list[MCPToolDescriptor]:
|
|
1628
|
+
from flowent.models import NodeType
|
|
1629
|
+
from flowent.tools import is_assistant_only_mcp_tool_name
|
|
1630
|
+
|
|
1625
1631
|
tools: list[MCPToolDescriptor] = []
|
|
1626
1632
|
for snapshot in self._visible_snapshots_for_agent(agent):
|
|
1627
|
-
tools.extend(
|
|
1633
|
+
tools.extend(
|
|
1634
|
+
descriptor
|
|
1635
|
+
for descriptor in snapshot.tools
|
|
1636
|
+
if agent.node_type == NodeType.ASSISTANT
|
|
1637
|
+
or not is_assistant_only_mcp_tool_name(descriptor.tool_name)
|
|
1638
|
+
)
|
|
1628
1639
|
return tools
|
|
1629
1640
|
|
|
1630
1641
|
def has_visible_capabilities(self, agent: Agent) -> bool:
|
|
@@ -1670,13 +1681,16 @@ class MCPService:
|
|
|
1670
1681
|
return prompts
|
|
1671
1682
|
|
|
1672
1683
|
def _get_server_for_agent(self, agent: Agent, server_name: str) -> MCPServerConfig:
|
|
1684
|
+
from flowent.graph_service import resolve_effective_permissions_for_agent
|
|
1685
|
+
|
|
1673
1686
|
if server_name not in self._visible_server_names_for_agent(agent):
|
|
1674
1687
|
raise MCPError(f"MCP server '{server_name}' is not globally available")
|
|
1675
1688
|
server = find_mcp_server(get_settings(), server_name)
|
|
1676
1689
|
if server is None or not server.enabled:
|
|
1677
1690
|
raise MCPError(f"MCP server '{server_name}' is unavailable")
|
|
1678
|
-
|
|
1679
|
-
|
|
1691
|
+
allow_network, _ = resolve_effective_permissions_for_agent(agent)
|
|
1692
|
+
if server.transport == "streamable_http" and not allow_network:
|
|
1693
|
+
raise MCPError("Network access is disabled for this workflow")
|
|
1680
1694
|
return server
|
|
1681
1695
|
|
|
1682
1696
|
def read_agent_resource(
|
|
@@ -34,6 +34,7 @@ def infer_model_capabilities(
|
|
|
34
34
|
model_id: str,
|
|
35
35
|
input_image: bool | None = None,
|
|
36
36
|
output_image: bool | None = None,
|
|
37
|
+
structured_output: bool | None = None,
|
|
37
38
|
) -> ModelCapabilities:
|
|
38
39
|
normalized_model_id = _normalize_model_id(model_id)
|
|
39
40
|
inferred_input_image = any(
|
|
@@ -53,6 +54,7 @@ def infer_model_capabilities(
|
|
|
53
54
|
return ModelCapabilities(
|
|
54
55
|
input_image=inferred_input_image if input_image is None else input_image,
|
|
55
56
|
output_image=(inferred_output_image if output_image is None else output_image),
|
|
57
|
+
structured_output=False if structured_output is None else structured_output,
|
|
56
58
|
)
|
|
57
59
|
|
|
58
60
|
|
|
@@ -80,6 +82,7 @@ def build_model_info(
|
|
|
80
82
|
model_id: str,
|
|
81
83
|
input_image: bool | None = None,
|
|
82
84
|
output_image: bool | None = None,
|
|
85
|
+
structured_output: bool | None = None,
|
|
83
86
|
context_window_tokens: int | None = None,
|
|
84
87
|
) -> ModelInfo:
|
|
85
88
|
return ModelInfo(
|
|
@@ -89,6 +92,7 @@ def build_model_info(
|
|
|
89
92
|
model_id=model_id,
|
|
90
93
|
input_image=input_image,
|
|
91
94
|
output_image=output_image,
|
|
95
|
+
structured_output=structured_output,
|
|
92
96
|
),
|
|
93
97
|
context_window_tokens=infer_context_window_tokens(
|
|
94
98
|
provider_type=provider_type,
|
|
@@ -30,6 +30,8 @@ from flowent.models.graph import (
|
|
|
30
30
|
GraphNodeRecord,
|
|
31
31
|
NodePosition,
|
|
32
32
|
PortDirection,
|
|
33
|
+
PortType,
|
|
34
|
+
WorkflowActivationState,
|
|
33
35
|
WorkflowDefinition,
|
|
34
36
|
WorkflowNodeDefinition,
|
|
35
37
|
WorkflowNodeKind,
|
|
@@ -42,9 +44,9 @@ from flowent.models.history import (
|
|
|
42
44
|
CommandResultEntry,
|
|
43
45
|
ErrorEntry,
|
|
44
46
|
HistoryEntry,
|
|
47
|
+
PortInboundEntry,
|
|
45
48
|
ReceivedMessage,
|
|
46
49
|
SentMessage,
|
|
47
|
-
StateEntry,
|
|
48
50
|
SystemEntry,
|
|
49
51
|
ToolCall,
|
|
50
52
|
)
|
|
@@ -94,12 +96,13 @@ __all__ = [
|
|
|
94
96
|
"NodePosition",
|
|
95
97
|
"NodeType",
|
|
96
98
|
"PortDirection",
|
|
99
|
+
"PortInboundEntry",
|
|
100
|
+
"PortType",
|
|
97
101
|
"ReceivedMessage",
|
|
98
102
|
"ReceivedMessageDelta",
|
|
99
103
|
"SentMessage",
|
|
100
104
|
"SentMessageDelta",
|
|
101
105
|
"Serializable",
|
|
102
|
-
"StateEntry",
|
|
103
106
|
"StreamingDelta",
|
|
104
107
|
"SystemEntry",
|
|
105
108
|
"Tab",
|
|
@@ -109,6 +112,7 @@ __all__ = [
|
|
|
109
112
|
"ToolCall",
|
|
110
113
|
"ToolCallResult",
|
|
111
114
|
"ToolResultDelta",
|
|
115
|
+
"WorkflowActivationState",
|
|
112
116
|
"WorkflowDefinition",
|
|
113
117
|
"WorkflowNodeDefinition",
|
|
114
118
|
"WorkflowNodeKind",
|
|
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
|
|
@@ -11,6 +11,7 @@ from flowent.models.todo import TodoItem
|
|
|
11
11
|
|
|
12
12
|
class WorkflowNodeKind(StrEnum):
|
|
13
13
|
TRIGGER = "trigger"
|
|
14
|
+
LLM = "llm"
|
|
14
15
|
AGENT = "agent"
|
|
15
16
|
CODE = "code"
|
|
16
17
|
IF = "if"
|
|
@@ -18,8 +19,14 @@ class WorkflowNodeKind(StrEnum):
|
|
|
18
19
|
|
|
19
20
|
|
|
20
21
|
class PortDirection(StrEnum):
|
|
21
|
-
INPUT = "
|
|
22
|
-
OUTPUT = "
|
|
22
|
+
INPUT = "in"
|
|
23
|
+
OUTPUT = "out"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class PortType(StrEnum):
|
|
27
|
+
PARTS = "parts"
|
|
28
|
+
STRING = "string"
|
|
29
|
+
JSON = "json"
|
|
23
30
|
|
|
24
31
|
|
|
25
32
|
class EdgeKind(StrEnum):
|
|
@@ -28,6 +35,29 @@ class EdgeKind(StrEnum):
|
|
|
28
35
|
EVENT = "event"
|
|
29
36
|
|
|
30
37
|
|
|
38
|
+
class WorkflowActivationState(StrEnum):
|
|
39
|
+
INACTIVE = "inactive"
|
|
40
|
+
ACTIVE = "active"
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _parse_port_direction(raw_direction: object) -> PortDirection:
|
|
44
|
+
if raw_direction == "input":
|
|
45
|
+
return PortDirection.INPUT
|
|
46
|
+
if raw_direction == "output":
|
|
47
|
+
return PortDirection.OUTPUT
|
|
48
|
+
return PortDirection(str(raw_direction))
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _port_type_from_legacy_kind(raw_kind: object) -> PortType | None:
|
|
52
|
+
try:
|
|
53
|
+
kind = EdgeKind(str(raw_kind))
|
|
54
|
+
except ValueError:
|
|
55
|
+
return None
|
|
56
|
+
if kind == EdgeKind.DATA:
|
|
57
|
+
return PortType.JSON
|
|
58
|
+
return PortType.PARTS
|
|
59
|
+
|
|
60
|
+
|
|
31
61
|
@dataclass
|
|
32
62
|
class NodePosition:
|
|
33
63
|
x: float
|
|
@@ -51,7 +81,7 @@ class NodePosition:
|
|
|
51
81
|
class WorkflowPort:
|
|
52
82
|
key: str
|
|
53
83
|
direction: PortDirection
|
|
54
|
-
|
|
84
|
+
type: PortType
|
|
55
85
|
required: bool = False
|
|
56
86
|
multiple: bool = False
|
|
57
87
|
|
|
@@ -59,7 +89,7 @@ class WorkflowPort:
|
|
|
59
89
|
return {
|
|
60
90
|
"key": self.key,
|
|
61
91
|
"direction": self.direction.value,
|
|
62
|
-
"
|
|
92
|
+
"type": self.type.value,
|
|
63
93
|
"required": self.required,
|
|
64
94
|
"multiple": self.multiple,
|
|
65
95
|
}
|
|
@@ -68,18 +98,24 @@ class WorkflowPort:
|
|
|
68
98
|
def from_mapping(cls, data: dict[str, object]) -> WorkflowPort | None:
|
|
69
99
|
key = data.get("key")
|
|
70
100
|
direction = data.get("direction")
|
|
71
|
-
|
|
101
|
+
port_type = data.get("type")
|
|
72
102
|
if not isinstance(key, str) or not key.strip():
|
|
73
103
|
return None
|
|
74
104
|
try:
|
|
75
|
-
parsed_direction =
|
|
76
|
-
parsed_kind = EdgeKind(str(kind))
|
|
105
|
+
parsed_direction = _parse_port_direction(direction)
|
|
77
106
|
except ValueError:
|
|
78
107
|
return None
|
|
108
|
+
try:
|
|
109
|
+
parsed_type = PortType(str(port_type))
|
|
110
|
+
except ValueError:
|
|
111
|
+
legacy_type = _port_type_from_legacy_kind(data.get("kind"))
|
|
112
|
+
if legacy_type is None:
|
|
113
|
+
return None
|
|
114
|
+
parsed_type = legacy_type
|
|
79
115
|
return cls(
|
|
80
116
|
key=key.strip(),
|
|
81
117
|
direction=parsed_direction,
|
|
82
|
-
|
|
118
|
+
type=parsed_type,
|
|
83
119
|
required=bool(data.get("required", False)),
|
|
84
120
|
multiple=bool(data.get("multiple", False)),
|
|
85
121
|
)
|
|
@@ -103,7 +139,6 @@ class GraphEdge:
|
|
|
103
139
|
"from_port_key": self.from_port_key,
|
|
104
140
|
"to_node_id": self.to_node_id,
|
|
105
141
|
"to_port_key": self.to_port_key,
|
|
106
|
-
"kind": self.kind.value,
|
|
107
142
|
"created_at": self.created_at,
|
|
108
143
|
}
|
|
109
144
|
if self.tab_id is not None:
|
|
@@ -24,6 +24,9 @@ class ReceivedMessage(Serializable):
|
|
|
24
24
|
parts: list[ContentPart] = field(default_factory=list)
|
|
25
25
|
content: str = ""
|
|
26
26
|
message_id: str | None = None
|
|
27
|
+
from_output_port_key: str | None = None
|
|
28
|
+
to_input_port_key: str | None = None
|
|
29
|
+
value_summary: str | None = None
|
|
27
30
|
timestamp: float = field(default_factory=time.time)
|
|
28
31
|
|
|
29
32
|
def __post_init__(self) -> None:
|
|
@@ -52,6 +55,9 @@ class SentMessage(Serializable):
|
|
|
52
55
|
parts: list[ContentPart] = field(default_factory=list)
|
|
53
56
|
content: str = ""
|
|
54
57
|
message_id: str | None = None
|
|
58
|
+
from_output_port_key: str | None = None
|
|
59
|
+
to_input_port_key: str | None = None
|
|
60
|
+
value_summary: str | None = None
|
|
55
61
|
timestamp: float = field(default_factory=time.time)
|
|
56
62
|
|
|
57
63
|
def __post_init__(self) -> None:
|
|
@@ -67,13 +73,6 @@ class AssistantThinking(Serializable):
|
|
|
67
73
|
timestamp: float = field(default_factory=time.time)
|
|
68
74
|
|
|
69
75
|
|
|
70
|
-
@dataclass
|
|
71
|
-
class StateEntry(Serializable):
|
|
72
|
-
state: str
|
|
73
|
-
reason: str = ""
|
|
74
|
-
timestamp: float = field(default_factory=time.time)
|
|
75
|
-
|
|
76
|
-
|
|
77
76
|
@dataclass
|
|
78
77
|
class ToolCall(Serializable):
|
|
79
78
|
tool_name: str
|
|
@@ -98,16 +97,28 @@ class CommandResultEntry(Serializable):
|
|
|
98
97
|
timestamp: float = field(default_factory=time.time)
|
|
99
98
|
|
|
100
99
|
|
|
100
|
+
@dataclass
|
|
101
|
+
class PortInboundEntry(Serializable):
|
|
102
|
+
from_id: str
|
|
103
|
+
from_output_port_key: str
|
|
104
|
+
to_input_port_key: str
|
|
105
|
+
port_type: str
|
|
106
|
+
value: Any
|
|
107
|
+
source_label: str | None = None
|
|
108
|
+
value_summary: str | None = None
|
|
109
|
+
timestamp: float = field(default_factory=time.time)
|
|
110
|
+
|
|
111
|
+
|
|
101
112
|
HistoryEntry = (
|
|
102
113
|
SystemEntry
|
|
103
114
|
| ReceivedMessage
|
|
104
115
|
| AssistantText
|
|
105
116
|
| SentMessage
|
|
106
117
|
| AssistantThinking
|
|
107
|
-
| StateEntry
|
|
108
118
|
| ToolCall
|
|
109
119
|
| ErrorEntry
|
|
110
120
|
| CommandResultEntry
|
|
121
|
+
| PortInboundEntry
|
|
111
122
|
)
|
|
112
123
|
|
|
113
124
|
|
|
@@ -135,6 +146,21 @@ def deserialize_history_entry(data: dict[str, Any]) -> HistoryEntry:
|
|
|
135
146
|
if isinstance(data.get("message_id"), str)
|
|
136
147
|
else None
|
|
137
148
|
),
|
|
149
|
+
from_output_port_key=(
|
|
150
|
+
str(data["from_output_port_key"])
|
|
151
|
+
if isinstance(data.get("from_output_port_key"), str)
|
|
152
|
+
else None
|
|
153
|
+
),
|
|
154
|
+
to_input_port_key=(
|
|
155
|
+
str(data["to_input_port_key"])
|
|
156
|
+
if isinstance(data.get("to_input_port_key"), str)
|
|
157
|
+
else None
|
|
158
|
+
),
|
|
159
|
+
value_summary=(
|
|
160
|
+
str(data["value_summary"])
|
|
161
|
+
if isinstance(data.get("value_summary"), str)
|
|
162
|
+
else None
|
|
163
|
+
),
|
|
138
164
|
timestamp=timestamp_value,
|
|
139
165
|
)
|
|
140
166
|
if entry_type == "AssistantText":
|
|
@@ -172,6 +198,21 @@ def deserialize_history_entry(data: dict[str, Any]) -> HistoryEntry:
|
|
|
172
198
|
if isinstance(data.get("message_id"), str)
|
|
173
199
|
else None
|
|
174
200
|
),
|
|
201
|
+
from_output_port_key=(
|
|
202
|
+
str(data["from_output_port_key"])
|
|
203
|
+
if isinstance(data.get("from_output_port_key"), str)
|
|
204
|
+
else None
|
|
205
|
+
),
|
|
206
|
+
to_input_port_key=(
|
|
207
|
+
str(data["to_input_port_key"])
|
|
208
|
+
if isinstance(data.get("to_input_port_key"), str)
|
|
209
|
+
else None
|
|
210
|
+
),
|
|
211
|
+
value_summary=(
|
|
212
|
+
str(data["value_summary"])
|
|
213
|
+
if isinstance(data.get("value_summary"), str)
|
|
214
|
+
else None
|
|
215
|
+
),
|
|
175
216
|
timestamp=timestamp_value,
|
|
176
217
|
)
|
|
177
218
|
if entry_type == "AssistantThinking":
|
|
@@ -179,12 +220,6 @@ def deserialize_history_entry(data: dict[str, Any]) -> HistoryEntry:
|
|
|
179
220
|
content=str(data.get("content", "")),
|
|
180
221
|
timestamp=timestamp_value,
|
|
181
222
|
)
|
|
182
|
-
if entry_type == "StateEntry":
|
|
183
|
-
return StateEntry(
|
|
184
|
-
state=str(data.get("state", "")),
|
|
185
|
-
reason=str(data.get("reason", "")),
|
|
186
|
-
timestamp=timestamp_value,
|
|
187
|
-
)
|
|
188
223
|
if entry_type == "ToolCall":
|
|
189
224
|
arguments = data.get("arguments")
|
|
190
225
|
return ToolCall(
|
|
@@ -207,8 +242,31 @@ def deserialize_history_entry(data: dict[str, Any]) -> HistoryEntry:
|
|
|
207
242
|
include_in_context=bool(data.get("include_in_context", False)),
|
|
208
243
|
timestamp=timestamp_value,
|
|
209
244
|
)
|
|
245
|
+
if entry_type == "PortInboundEntry":
|
|
246
|
+
return PortInboundEntry(
|
|
247
|
+
from_id=str(data.get("from_id", "")),
|
|
248
|
+
from_output_port_key=str(data.get("from_output_port_key", "")),
|
|
249
|
+
to_input_port_key=str(data.get("to_input_port_key", "")),
|
|
250
|
+
port_type=str(data.get("port_type", "")),
|
|
251
|
+
value=data.get("value"),
|
|
252
|
+
source_label=(
|
|
253
|
+
str(data["source_label"])
|
|
254
|
+
if isinstance(data.get("source_label"), str)
|
|
255
|
+
else None
|
|
256
|
+
),
|
|
257
|
+
value_summary=(
|
|
258
|
+
str(data["value_summary"])
|
|
259
|
+
if isinstance(data.get("value_summary"), str)
|
|
260
|
+
else None
|
|
261
|
+
),
|
|
262
|
+
timestamp=timestamp_value,
|
|
263
|
+
)
|
|
210
264
|
raise ValueError(f"Unknown history entry type: {entry_type}")
|
|
211
265
|
|
|
212
266
|
|
|
213
267
|
def deserialize_history_entries(items: list[dict[str, Any]]) -> list[HistoryEntry]:
|
|
214
|
-
return [
|
|
268
|
+
return [
|
|
269
|
+
deserialize_history_entry(item)
|
|
270
|
+
for item in items
|
|
271
|
+
if item.get("type") != "StateEntry"
|
|
272
|
+
]
|
|
@@ -18,6 +18,12 @@ class Message:
|
|
|
18
18
|
content: str = ""
|
|
19
19
|
message_id: str | None = None
|
|
20
20
|
history_recorded: bool = False
|
|
21
|
+
from_output_port_key: str | None = None
|
|
22
|
+
to_input_port_key: str | None = None
|
|
23
|
+
port_type: str | None = None
|
|
24
|
+
value: object | None = None
|
|
25
|
+
value_summary: str | None = None
|
|
26
|
+
port_inbound_recorded: bool = False
|
|
21
27
|
timestamp: float = field(default_factory=time.time)
|
|
22
28
|
|
|
23
29
|
def __post_init__(self) -> None:
|
|
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|
|
3
3
|
import time
|
|
4
4
|
from dataclasses import dataclass, field
|
|
5
5
|
|
|
6
|
-
from flowent.models.graph import WorkflowDefinition
|
|
6
|
+
from flowent.models.graph import WorkflowActivationState, WorkflowDefinition
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
@dataclass
|
|
@@ -12,6 +12,10 @@ class Tab:
|
|
|
12
12
|
title: str
|
|
13
13
|
leader_id: str | None = None
|
|
14
14
|
definition: WorkflowDefinition = field(default_factory=WorkflowDefinition)
|
|
15
|
+
activation_state: WorkflowActivationState = WorkflowActivationState.INACTIVE
|
|
16
|
+
allow_network: bool = False
|
|
17
|
+
write_dirs: list[str] = field(default_factory=list)
|
|
18
|
+
permissions_initialized: bool = False
|
|
15
19
|
created_at: float = field(default_factory=time.time)
|
|
16
20
|
updated_at: float = field(default_factory=time.time)
|
|
17
21
|
|
|
@@ -21,15 +25,40 @@ class Tab:
|
|
|
21
25
|
"title": self.title,
|
|
22
26
|
"leader_id": self.leader_id,
|
|
23
27
|
"definition": self.definition.serialize(),
|
|
28
|
+
"activation_state": self.activation_state.value,
|
|
29
|
+
"allow_network": self.allow_network,
|
|
30
|
+
"write_dirs": list(self.write_dirs),
|
|
31
|
+
"permissions_initialized": self.permissions_initialized,
|
|
24
32
|
"created_at": self.created_at,
|
|
25
33
|
"updated_at": self.updated_at,
|
|
26
34
|
}
|
|
27
35
|
|
|
28
36
|
@classmethod
|
|
29
37
|
def from_mapping(cls, data: dict[str, object]) -> Tab:
|
|
38
|
+
from flowent.settings import build_assistant_write_dirs
|
|
39
|
+
|
|
30
40
|
created_at = data.get("created_at")
|
|
31
41
|
updated_at = data.get("updated_at")
|
|
32
42
|
raw_definition = data.get("definition")
|
|
43
|
+
raw_activation_state = data.get("activation_state")
|
|
44
|
+
raw_permissions_initialized = data.get("permissions_initialized")
|
|
45
|
+
raw_write_dirs_value = data.get("write_dirs")
|
|
46
|
+
raw_write_dirs = (
|
|
47
|
+
[item for item in raw_write_dirs_value if isinstance(item, str)]
|
|
48
|
+
if isinstance(raw_write_dirs_value, list)
|
|
49
|
+
else []
|
|
50
|
+
)
|
|
51
|
+
try:
|
|
52
|
+
write_dirs = build_assistant_write_dirs(
|
|
53
|
+
raw_write_dirs,
|
|
54
|
+
field_name="write_dirs",
|
|
55
|
+
)
|
|
56
|
+
except ValueError:
|
|
57
|
+
write_dirs = []
|
|
58
|
+
try:
|
|
59
|
+
activation_state = WorkflowActivationState(str(raw_activation_state))
|
|
60
|
+
except ValueError:
|
|
61
|
+
activation_state = WorkflowActivationState.INACTIVE
|
|
33
62
|
return cls(
|
|
34
63
|
id=str(data.get("id", "")),
|
|
35
64
|
title=str(data.get("title", "")),
|
|
@@ -39,6 +68,14 @@ class Tab:
|
|
|
39
68
|
definition=WorkflowDefinition.from_mapping(
|
|
40
69
|
raw_definition if isinstance(raw_definition, dict) else None
|
|
41
70
|
),
|
|
71
|
+
activation_state=activation_state,
|
|
72
|
+
allow_network=bool(data.get("allow_network", False)),
|
|
73
|
+
write_dirs=write_dirs,
|
|
74
|
+
permissions_initialized=(
|
|
75
|
+
bool(raw_permissions_initialized)
|
|
76
|
+
or "allow_network" in data
|
|
77
|
+
or "write_dirs" in data
|
|
78
|
+
),
|
|
42
79
|
created_at=created_at
|
|
43
80
|
if isinstance(created_at, (int, float))
|
|
44
81
|
else time.time(),
|
|
@@ -11,7 +11,7 @@ from typing import Any, Literal
|
|
|
11
11
|
from flowent.models import LLMUsage
|
|
12
12
|
from flowent.state_db import open_state_db
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
OBSERVABILITY_RETENTION_SECONDS = 30 * 24 * 60 * 60
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
def serialize_usage(usage: LLMUsage | None) -> dict[str, Any] | None:
|
|
@@ -66,7 +66,7 @@ class CompactRecordInput:
|
|
|
66
66
|
error_summary: str | None = None
|
|
67
67
|
|
|
68
68
|
|
|
69
|
-
class
|
|
69
|
+
class ObservabilityStore:
|
|
70
70
|
def __init__(self) -> None:
|
|
71
71
|
self._lock = threading.Lock()
|
|
72
72
|
|
|
@@ -82,7 +82,7 @@ class StatsStore:
|
|
|
82
82
|
connection.close()
|
|
83
83
|
|
|
84
84
|
def _prune_locked(self, connection, now: float) -> None:
|
|
85
|
-
min_timestamp = now -
|
|
85
|
+
min_timestamp = now - OBSERVABILITY_RETENTION_SECONDS
|
|
86
86
|
connection.execute(
|
|
87
87
|
"DELETE FROM llm_request_records WHERE ended_at < ?",
|
|
88
88
|
(min_timestamp,),
|
|
@@ -215,4 +215,4 @@ class StatsStore:
|
|
|
215
215
|
return records
|
|
216
216
|
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
observability_store = ObservabilityStore()
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -47,9 +47,9 @@ SET_PERMISSIONS_TOOL_GUIDANCE = """\
|
|
|
47
47
|
## Set Permissions Tool Rules
|
|
48
48
|
|
|
49
49
|
- Use `set_permissions` to patch a workflow's permission boundary after the workflow already exists.
|
|
50
|
-
- `set_permissions` updates the target workflow
|
|
50
|
+
- `set_permissions` updates the target workflow's own `allow_network` and `write_dirs`.
|
|
51
51
|
- Treat `allow_network` and `write_dirs` as patch fields: omitted fields stay unchanged.
|
|
52
|
-
- When the Human asks to change a workflow's network or writable directory boundary, prefer `set_permissions
|
|
52
|
+
- When the Human asks to change a workflow's network or writable directory boundary, prefer `set_permissions`.
|
|
53
53
|
"""
|
|
54
54
|
|
|
55
55
|
CREATE_AGENT_TOOL_GUIDANCE = """\
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
STEWARD_ROLE_SYSTEM_PROMPT = """\
|
|
2
2
|
You are the Steward role currently used by the Assistant - the Human's interface to the system.
|
|
3
3
|
|
|
4
|
-
The Human can interact with the system
|
|
4
|
+
The Human can interact with the system through the Assistant chat panel and through the current workflow chat. The Human has no terminal, filesystem access, or direct execution surface. If a request requires reading files, running commands, editing code, browsing the network, or any other system interaction, you must open a workflow and create the appropriate agents to do the work rather than pushing the task back to the Human.
|
|
5
5
|
|
|
6
6
|
Your responsibilities:
|
|
7
7
|
- Understand the Human's intent
|
|
@@ -30,7 +30,7 @@ Your responsibilities:
|
|
|
30
30
|
|
|
31
31
|
- You can manage system configuration directly without creating an agent
|
|
32
32
|
- When the Human asks about current system configuration or wants to change providers, roles, settings, or prompts, use the corresponding management tool directly
|
|
33
|
-
- When the Human asks to change an existing workflow's network or writable-directory boundary, use `set_permissions` directly
|
|
33
|
+
- When the Human asks to change an existing workflow's network or writable-directory boundary, use `set_permissions` directly
|
|
34
34
|
|
|
35
35
|
## Security Boundary
|
|
36
36
|
|
|
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
|
|
Binary file
|