flowent 0.0.6 → 0.0.7
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 +1 -1
- package/backend/pyproject.toml +1 -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__/model_metadata.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/network.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/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 +91 -8
- 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/graph_service.py +3 -110
- 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/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/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/role_management.py +9 -6
- 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__/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 +3 -0
- package/backend/src/flowent/routes/nodes.py +11 -1
- package/backend/src/flowent/routes/settings.py +169 -118
- package/backend/src/flowent/routes/tabs.py +0 -12
- package/backend/src/flowent/runtime.py +0 -5
- package/backend/src/flowent/security.py +1 -21
- package/backend/src/flowent/settings.py +15 -421
- package/backend/src/flowent/settings_management.py +260 -164
- package/backend/src/flowent/state_db.py +2 -14
- package/backend/src/flowent/static/assets/AssistantPage-BW7XAd9I.js +1 -0
- package/backend/src/flowent/static/assets/ChannelsPage-tCJHgt6m.js +1 -0
- package/backend/src/flowent/static/assets/{PageScaffold-DteOA8V7.js → PageScaffold-f6g2l7XN.js} +1 -1
- package/backend/src/flowent/static/assets/PromptsPage-C3Sxn2D7.js +1 -0
- package/backend/src/flowent/static/assets/ProvidersPage-BfmdXmNt.js +3 -0
- package/backend/src/flowent/static/assets/RolesPage-DET8wO4r.js +1 -0
- package/backend/src/flowent/static/assets/SettingsPage-D-g3deMm.js +3 -0
- package/backend/src/flowent/static/assets/ToolsPage-CDmtE2g4.js +1 -0
- package/backend/src/flowent/static/assets/WorkspacePage-AZsJ0sD0.js +3 -0
- package/backend/src/flowent/static/assets/WorkspacePanels-CteCjolX.js +1 -0
- package/backend/src/flowent/static/assets/{alert-dialog-DIBUCmqM.js → alert-dialog-Duorp_S-.js} +1 -1
- package/backend/src/flowent/static/assets/{dialog-BOvHIBrg.js → dialog-C3ixjGjN.js} +1 -1
- package/backend/src/flowent/static/assets/index--o_0fv0N.css +1 -0
- package/backend/src/flowent/static/assets/index-C9HuekJm.js +10 -0
- package/backend/src/flowent/static/assets/{modelParams-DcEhGnu0.js → modelParams-DmnF2hwR.js} +1 -1
- package/backend/src/flowent/static/assets/providerTypes-DT3Ahwl_.js +1 -0
- package/backend/src/flowent/static/assets/roles-CuRT_chR.js +1 -0
- package/{dist/frontend/assets/select-D9SwnlXF.js → backend/src/flowent/static/assets/select-DCfeNu-F.js} +1 -1
- package/backend/src/flowent/static/assets/surface-pWwG5ogx.js +1 -0
- package/backend/src/flowent/static/assets/{ui-vendor-UazN8rcv.js → ui-vendor-C5pJa8N7.js} +15 -15
- package/backend/src/flowent/static/assets/useAppRoute-FgSHBKhV.js +1 -0
- package/backend/src/flowent/static/index.html +3 -3
- package/backend/src/flowent/tools/__init__.py +2 -101
- 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__/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/list_roles.py +2 -9
- package/backend/src/flowent/tools/manage_settings.py +134 -172
- 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_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 +68 -0
- package/backend/tests/integration/api/test_meta_api.py +0 -1
- package/backend/tests/integration/api/test_nodes_api.py +73 -8
- package/backend/tests/integration/api/test_tabs_api.py +0 -114
- 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 +0 -15
- package/backend/tests/unit/agent/test_agent_runtime.py +148 -2
- 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/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_prompts_routes.py +0 -22
- package/backend/tests/unit/routes/test_roles_routes.py +6 -2
- package/backend/tests/unit/routes/test_settings_routes.py +0 -19
- package/backend/tests/unit/runtime/__pycache__/test_bootstrap_runtime.cpython-313-pytest-9.0.3.pyc +0 -0
- 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/settings/__pycache__/test_settings_roles.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/settings/test_settings_roles.py +3 -51
- package/backend/tests/unit/test_cli.py +0 -22
- package/backend/tests/unit/test_state_sqlite_storage.py +27 -99
- package/backend/tests/unit/test_workspace_store.py +0 -3
- 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_create_agent_tool.py +0 -32
- package/backend/tests/unit/tools/test_manage_prompts_tool.py +5 -30
- package/backend/tests/unit/tools/test_tool_registry.py +45 -40
- package/backend/uv.lock +1 -1
- package/dist/frontend/assets/AssistantPage-BW7XAd9I.js +1 -0
- package/dist/frontend/assets/ChannelsPage-tCJHgt6m.js +1 -0
- package/dist/frontend/assets/{PageScaffold-DteOA8V7.js → PageScaffold-f6g2l7XN.js} +1 -1
- package/dist/frontend/assets/PromptsPage-C3Sxn2D7.js +1 -0
- package/dist/frontend/assets/ProvidersPage-BfmdXmNt.js +3 -0
- package/dist/frontend/assets/RolesPage-DET8wO4r.js +1 -0
- package/dist/frontend/assets/SettingsPage-D-g3deMm.js +3 -0
- package/dist/frontend/assets/ToolsPage-CDmtE2g4.js +1 -0
- package/dist/frontend/assets/WorkspacePage-AZsJ0sD0.js +3 -0
- package/dist/frontend/assets/WorkspacePanels-CteCjolX.js +1 -0
- package/dist/frontend/assets/{alert-dialog-DIBUCmqM.js → alert-dialog-Duorp_S-.js} +1 -1
- package/dist/frontend/assets/{dialog-BOvHIBrg.js → dialog-C3ixjGjN.js} +1 -1
- package/dist/frontend/assets/index--o_0fv0N.css +1 -0
- package/dist/frontend/assets/index-C9HuekJm.js +10 -0
- package/dist/frontend/assets/{modelParams-DcEhGnu0.js → modelParams-DmnF2hwR.js} +1 -1
- package/dist/frontend/assets/providerTypes-DT3Ahwl_.js +1 -0
- package/dist/frontend/assets/roles-CuRT_chR.js +1 -0
- package/{backend/src/flowent/static/assets/select-D9SwnlXF.js → dist/frontend/assets/select-DCfeNu-F.js} +1 -1
- package/dist/frontend/assets/surface-pWwG5ogx.js +1 -0
- package/dist/frontend/assets/{ui-vendor-UazN8rcv.js → ui-vendor-C5pJa8N7.js} +15 -15
- package/dist/frontend/assets/useAppRoute-FgSHBKhV.js +1 -0
- package/dist/frontend/index.html +3 -3
- package/package.json +1 -1
- package/backend/src/flowent/__pycache__/mcp_service.cpython-313.pyc +0 -0
- package/backend/src/flowent/mcp_service.py +0 -1918
- package/backend/src/flowent/routes/__pycache__/mcp.cpython-313.pyc +0 -0
- package/backend/src/flowent/routes/mcp.py +0 -125
- package/backend/src/flowent/static/assets/AssistantPage-VBohhz4d.js +0 -1
- package/backend/src/flowent/static/assets/ChannelsPage-CIydPZA_.js +0 -1
- package/backend/src/flowent/static/assets/McpPage-CHPm2TPY.js +0 -7
- package/backend/src/flowent/static/assets/PromptsPage-CSmJ3sZg.js +0 -1
- package/backend/src/flowent/static/assets/ProvidersPage-sl2jeG4e.js +0 -3
- package/backend/src/flowent/static/assets/RolesPage-DCe7W6Km.js +0 -1
- package/backend/src/flowent/static/assets/SettingsPage-Bix9e63E.js +0 -3
- package/backend/src/flowent/static/assets/ToolsPage-favNkj5C.js +0 -1
- package/backend/src/flowent/static/assets/WorkspaceCommandDialog-DRS6wiD6.js +0 -1
- package/backend/src/flowent/static/assets/WorkspacePage-KuaDjt_D.js +0 -3
- package/backend/src/flowent/static/assets/WorkspacePanels-BZxBw8M5.js +0 -1
- package/backend/src/flowent/static/assets/datetime-eJqd0V2S.js +0 -1
- package/backend/src/flowent/static/assets/index-Biio-CoI.js +0 -10
- package/backend/src/flowent/static/assets/index-CmQvO7sl.css +0 -1
- package/backend/src/flowent/static/assets/roles-BbIEIMeG.js +0 -1
- package/backend/src/flowent/static/assets/surface-Bzr1FRG4.js +0 -1
- package/backend/src/flowent/static/assets/triState-DgLlKdRR.js +0 -1
- package/backend/src/flowent/tools/__pycache__/mcp.cpython-313.pyc +0 -0
- package/backend/src/flowent/tools/mcp.py +0 -199
- package/backend/tests/integration/api/__pycache__/test_mcp_api.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/integration/api/test_mcp_api.py +0 -116
- package/dist/frontend/assets/AssistantPage-VBohhz4d.js +0 -1
- package/dist/frontend/assets/ChannelsPage-CIydPZA_.js +0 -1
- package/dist/frontend/assets/McpPage-CHPm2TPY.js +0 -7
- package/dist/frontend/assets/PromptsPage-CSmJ3sZg.js +0 -1
- package/dist/frontend/assets/ProvidersPage-sl2jeG4e.js +0 -3
- package/dist/frontend/assets/RolesPage-DCe7W6Km.js +0 -1
- package/dist/frontend/assets/SettingsPage-Bix9e63E.js +0 -3
- package/dist/frontend/assets/ToolsPage-favNkj5C.js +0 -1
- package/dist/frontend/assets/WorkspaceCommandDialog-DRS6wiD6.js +0 -1
- package/dist/frontend/assets/WorkspacePage-KuaDjt_D.js +0 -3
- package/dist/frontend/assets/WorkspacePanels-BZxBw8M5.js +0 -1
- package/dist/frontend/assets/datetime-eJqd0V2S.js +0 -1
- package/dist/frontend/assets/index-Biio-CoI.js +0 -10
- package/dist/frontend/assets/index-CmQvO7sl.css +0 -1
- package/dist/frontend/assets/roles-BbIEIMeG.js +0 -1
- package/dist/frontend/assets/surface-Bzr1FRG4.js +0 -1
- package/dist/frontend/assets/triState-DgLlKdRR.js +0 -1
package/backend/tests/integration/api/__pycache__/test_prompts_api.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/integration/api/__pycache__/test_roles_api.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/integration/api/__pycache__/test_tabs_api.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import base64
|
|
2
|
+
import threading
|
|
2
3
|
from uuid import UUID
|
|
3
4
|
|
|
4
5
|
from flowent.models import (
|
|
6
|
+
AgentState,
|
|
5
7
|
AssistantText,
|
|
8
|
+
ErrorEntry,
|
|
6
9
|
ImagePart,
|
|
7
10
|
LLMResponse,
|
|
8
11
|
ReceivedMessage,
|
|
9
12
|
TextPart,
|
|
10
13
|
)
|
|
14
|
+
from flowent.providers.errors import LLMProviderError
|
|
11
15
|
from flowent.registry import registry
|
|
12
16
|
|
|
13
17
|
_ONE_PIXEL_PNG = base64.b64decode(
|
|
@@ -77,6 +81,70 @@ def test_clear_command_clears_history_back_to_empty_state(client):
|
|
|
77
81
|
)
|
|
78
82
|
|
|
79
83
|
|
|
84
|
+
def test_assistant_accepts_new_message_after_error(monkeypatch, client):
|
|
85
|
+
assistant_id = _get_assistant_id(client)
|
|
86
|
+
assistant = registry.get(assistant_id)
|
|
87
|
+
assert assistant is not None
|
|
88
|
+
chat_started = threading.Event()
|
|
89
|
+
release_chat = threading.Event()
|
|
90
|
+
|
|
91
|
+
def fake_chat(**kwargs):
|
|
92
|
+
chat_started.set()
|
|
93
|
+
release_chat.wait(timeout=2)
|
|
94
|
+
raise LLMProviderError(
|
|
95
|
+
"LLM API error\nDetail: still invalid",
|
|
96
|
+
transient=False,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
monkeypatch.setattr("flowent.agent.gateway.chat", fake_chat)
|
|
100
|
+
assistant.history.append(ErrorEntry(content="LLM API error\nDetail: Invalid key"))
|
|
101
|
+
assistant.set_state(AgentState.ERROR, "LLM API error")
|
|
102
|
+
|
|
103
|
+
try:
|
|
104
|
+
response = client.post(
|
|
105
|
+
"/api/assistant/message",
|
|
106
|
+
json={"content": "Continue with a safer plan"},
|
|
107
|
+
)
|
|
108
|
+
|
|
109
|
+
assert response.status_code == 200
|
|
110
|
+
message_id = response.json()["message_id"]
|
|
111
|
+
assert isinstance(message_id, str)
|
|
112
|
+
assert chat_started.wait(timeout=1)
|
|
113
|
+
|
|
114
|
+
detail = client.get(f"/api/nodes/{assistant_id}").json()
|
|
115
|
+
history = detail["history"]
|
|
116
|
+
assert any(
|
|
117
|
+
entry["type"] == "ErrorEntry"
|
|
118
|
+
and entry["content"] == "LLM API error\nDetail: Invalid key"
|
|
119
|
+
for entry in history
|
|
120
|
+
)
|
|
121
|
+
assert any(
|
|
122
|
+
entry["type"] == "ReceivedMessage"
|
|
123
|
+
and entry["from_id"] == "human"
|
|
124
|
+
and entry["message_id"] == message_id
|
|
125
|
+
and entry["content"] == "Continue with a safer plan"
|
|
126
|
+
for entry in history
|
|
127
|
+
)
|
|
128
|
+
assert registry.get(assistant_id).state == AgentState.RUNNING
|
|
129
|
+
finally:
|
|
130
|
+
release_chat.set()
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_assistant_rejects_message_when_terminated(client):
|
|
134
|
+
assistant_id = _get_assistant_id(client)
|
|
135
|
+
assistant = registry.get(assistant_id)
|
|
136
|
+
assert assistant is not None
|
|
137
|
+
assistant.set_state(AgentState.TERMINATED, "done")
|
|
138
|
+
|
|
139
|
+
response = client.post(
|
|
140
|
+
"/api/assistant/message",
|
|
141
|
+
json={"content": "Continue"},
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
assert response.status_code == 409
|
|
145
|
+
assert response.json()["detail"] == "Assistant is no longer available"
|
|
146
|
+
|
|
147
|
+
|
|
80
148
|
def test_compact_command_replaces_history_with_summary(monkeypatch, client):
|
|
81
149
|
assistant_id = _get_assistant_id(client)
|
|
82
150
|
assistant = registry.get(assistant_id)
|
|
@@ -6,7 +6,6 @@ def test_tools_api_shows_agent_visible_management_tools(client: TestClient):
|
|
|
6
6
|
|
|
7
7
|
assert response.status_code == 200
|
|
8
8
|
tool_names = {tool["name"] for tool in response.json()["tools"]}
|
|
9
|
-
assert "create_root" not in tool_names
|
|
10
9
|
assert "manage_providers" in tool_names
|
|
11
10
|
assert "manage_roles" in tool_names
|
|
12
11
|
assert "manage_settings" in tool_names
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import threading
|
|
2
3
|
import time
|
|
3
4
|
from uuid import UUID
|
|
4
5
|
|
|
@@ -7,13 +8,14 @@ from fastapi.testclient import TestClient
|
|
|
7
8
|
from flowent.models import (
|
|
8
9
|
AgentState,
|
|
9
10
|
AssistantText,
|
|
11
|
+
ErrorEntry,
|
|
10
12
|
ImagePart,
|
|
11
13
|
LLMResponse,
|
|
12
14
|
ReceivedMessage,
|
|
13
15
|
TextPart,
|
|
14
16
|
)
|
|
17
|
+
from flowent.providers.errors import LLMProviderError
|
|
15
18
|
from flowent.registry import registry
|
|
16
|
-
from flowent.routes.nodes import router as nodes_router
|
|
17
19
|
from flowent.settings import STEWARD_ROLE_INCLUDED_TOOLS
|
|
18
20
|
from flowent.tools import MINIMUM_TOOLS
|
|
19
21
|
|
|
@@ -135,13 +137,6 @@ def test_worker_contacts_follow_output_paths(
|
|
|
135
137
|
]
|
|
136
138
|
|
|
137
139
|
|
|
138
|
-
def test_direct_node_message_api_is_not_available(client: TestClient):
|
|
139
|
-
assert not any(
|
|
140
|
-
getattr(route, "path", None) == "/api/nodes/{node_id}/message"
|
|
141
|
-
for route in nodes_router.routes
|
|
142
|
-
)
|
|
143
|
-
|
|
144
|
-
|
|
145
140
|
def test_only_assistant_node_exists_at_startup(client: TestClient):
|
|
146
141
|
list_response = client.get("/api/nodes")
|
|
147
142
|
|
|
@@ -308,6 +303,76 @@ def test_unknown_slash_input_can_be_sent_directly_to_workflow_leader(
|
|
|
308
303
|
)
|
|
309
304
|
|
|
310
305
|
|
|
306
|
+
def test_leader_accepts_new_message_after_error(monkeypatch, client: TestClient):
|
|
307
|
+
tab = client.post(
|
|
308
|
+
"/api/workflows",
|
|
309
|
+
json={"title": "Execution", "allow_network": True},
|
|
310
|
+
).json()
|
|
311
|
+
leader = registry.get(tab["leader_id"])
|
|
312
|
+
assert leader is not None
|
|
313
|
+
chat_started = threading.Event()
|
|
314
|
+
release_chat = threading.Event()
|
|
315
|
+
|
|
316
|
+
def fake_chat(**kwargs):
|
|
317
|
+
chat_started.set()
|
|
318
|
+
release_chat.wait(timeout=2)
|
|
319
|
+
raise LLMProviderError(
|
|
320
|
+
"LLM API error\nDetail: still invalid",
|
|
321
|
+
transient=False,
|
|
322
|
+
)
|
|
323
|
+
|
|
324
|
+
monkeypatch.setattr("flowent.agent.gateway.chat", fake_chat)
|
|
325
|
+
leader.history.append(ErrorEntry(content="LLM API error\nDetail: Invalid key"))
|
|
326
|
+
leader.set_state(AgentState.ERROR, "LLM API error")
|
|
327
|
+
|
|
328
|
+
try:
|
|
329
|
+
response = client.post(
|
|
330
|
+
f"/api/nodes/{tab['leader_id']}/messages",
|
|
331
|
+
json={"content": "Continue the workflow chat"},
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
assert response.status_code == 200
|
|
335
|
+
message_id = response.json()["message_id"]
|
|
336
|
+
assert isinstance(message_id, str)
|
|
337
|
+
assert chat_started.wait(timeout=1)
|
|
338
|
+
|
|
339
|
+
detail = client.get(f"/api/nodes/{tab['leader_id']}").json()
|
|
340
|
+
history = detail["history"]
|
|
341
|
+
assert any(
|
|
342
|
+
entry["type"] == "ErrorEntry"
|
|
343
|
+
and entry["content"] == "LLM API error\nDetail: Invalid key"
|
|
344
|
+
for entry in history
|
|
345
|
+
)
|
|
346
|
+
assert any(
|
|
347
|
+
entry["type"] == "ReceivedMessage"
|
|
348
|
+
and entry["from_id"] == "human"
|
|
349
|
+
and entry["message_id"] == message_id
|
|
350
|
+
and entry["content"] == "Continue the workflow chat"
|
|
351
|
+
for entry in history
|
|
352
|
+
)
|
|
353
|
+
assert registry.get(tab["leader_id"]).state == AgentState.RUNNING
|
|
354
|
+
finally:
|
|
355
|
+
release_chat.set()
|
|
356
|
+
|
|
357
|
+
|
|
358
|
+
def test_leader_rejects_message_when_terminated(client: TestClient):
|
|
359
|
+
tab = client.post(
|
|
360
|
+
"/api/workflows",
|
|
361
|
+
json={"title": "Execution"},
|
|
362
|
+
).json()
|
|
363
|
+
leader = registry.get(tab["leader_id"])
|
|
364
|
+
assert leader is not None
|
|
365
|
+
leader.set_state(AgentState.TERMINATED, "done")
|
|
366
|
+
|
|
367
|
+
response = client.post(
|
|
368
|
+
f"/api/nodes/{tab['leader_id']}/messages",
|
|
369
|
+
json={"content": "Continue the workflow chat"},
|
|
370
|
+
)
|
|
371
|
+
|
|
372
|
+
assert response.status_code == 409
|
|
373
|
+
assert response.json()["detail"] == "This workflow chat is no longer available"
|
|
374
|
+
|
|
375
|
+
|
|
311
376
|
def test_leader_help_command_returns_visible_command_feedback(client: TestClient):
|
|
312
377
|
tab = client.post(
|
|
313
378
|
"/api/workflows",
|
|
@@ -46,24 +46,6 @@ def test_list_tabs_is_empty_at_startup(client: TestClient):
|
|
|
46
46
|
assert response.json() == {"workflows": []}
|
|
47
47
|
|
|
48
48
|
|
|
49
|
-
def test_create_tab_rejects_removed_mcp_servers_field(client: TestClient):
|
|
50
|
-
response = client.post(
|
|
51
|
-
"/api/workflows",
|
|
52
|
-
json={"title": "Review Task", "mcp_servers": ["filesystem"]},
|
|
53
|
-
)
|
|
54
|
-
|
|
55
|
-
assert response.status_code == 422
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
def test_create_tab_rejects_removed_goal_field(client: TestClient):
|
|
59
|
-
response = client.post(
|
|
60
|
-
"/api/workflows",
|
|
61
|
-
json={"title": "Review Task", "goal": "Inspect changed files"},
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
assert response.status_code == 422
|
|
65
|
-
|
|
66
|
-
|
|
67
49
|
def test_create_tab_node_and_edge_round_trip(client: TestClient):
|
|
68
50
|
create_tab_response = client.post(
|
|
69
51
|
"/api/workflows",
|
|
@@ -335,78 +317,6 @@ def test_tab_edge_creation_enforces_directed_ports_and_single_input(
|
|
|
335
317
|
)
|
|
336
318
|
|
|
337
319
|
|
|
338
|
-
def test_duplicate_tab_copies_definition_and_runtime_agents(client: TestClient):
|
|
339
|
-
source_tab = client.post(
|
|
340
|
-
"/api/workflows",
|
|
341
|
-
json={
|
|
342
|
-
"title": "Original Workflow",
|
|
343
|
-
"allow_network": True,
|
|
344
|
-
"write_dirs": ["/tmp"],
|
|
345
|
-
},
|
|
346
|
-
).json()
|
|
347
|
-
source_tab_id = source_tab["id"]
|
|
348
|
-
|
|
349
|
-
reviewer = _create_agent_node(client, tab_id=source_tab_id, name="Reviewer")
|
|
350
|
-
formatter = _create_graph_node(
|
|
351
|
-
client,
|
|
352
|
-
tab_id=source_tab_id,
|
|
353
|
-
node_type="code",
|
|
354
|
-
name="Formatter",
|
|
355
|
-
config={"language": "python"},
|
|
356
|
-
)
|
|
357
|
-
source_detail = client.get(f"/api/workflows/{source_tab_id}").json()
|
|
358
|
-
source_definition = deepcopy(source_detail["workflow"]["definition"])
|
|
359
|
-
source_definition["view"] = {
|
|
360
|
-
"positions": {
|
|
361
|
-
reviewer["id"]: {"x": 20, "y": 40},
|
|
362
|
-
formatter["id"]: {"x": 180, "y": 40},
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
source_definition["edges"] = [
|
|
366
|
-
{
|
|
367
|
-
"id": "edge-review",
|
|
368
|
-
"from_node_id": reviewer["id"],
|
|
369
|
-
"from_port_key": "out",
|
|
370
|
-
"to_node_id": formatter["id"],
|
|
371
|
-
"to_port_key": "in",
|
|
372
|
-
}
|
|
373
|
-
]
|
|
374
|
-
update_response = client.put(
|
|
375
|
-
f"/api/workflows/{source_tab_id}/definition",
|
|
376
|
-
json={"definition": source_definition},
|
|
377
|
-
)
|
|
378
|
-
assert update_response.status_code == 200
|
|
379
|
-
|
|
380
|
-
duplicate_response = client.post(f"/api/workflows/{source_tab_id}/duplicate")
|
|
381
|
-
|
|
382
|
-
assert duplicate_response.status_code == 200
|
|
383
|
-
duplicated_tab = duplicate_response.json()
|
|
384
|
-
assert duplicated_tab["title"] == "Original Workflow Copy"
|
|
385
|
-
assert "goal" not in duplicated_tab
|
|
386
|
-
assert duplicated_tab["node_count"] == 2
|
|
387
|
-
assert duplicated_tab["edge_count"] == 1
|
|
388
|
-
assert duplicated_tab["id"] != source_tab_id
|
|
389
|
-
assert duplicated_tab["leader_id"] != source_tab["leader_id"]
|
|
390
|
-
assert duplicated_tab["activation_state"] == "inactive"
|
|
391
|
-
assert duplicated_tab["allow_network"] is True
|
|
392
|
-
assert duplicated_tab["write_dirs"] == ["/tmp"]
|
|
393
|
-
|
|
394
|
-
duplicated_detail = client.get(f"/api/workflows/{duplicated_tab['id']}").json()
|
|
395
|
-
assert "goal" not in duplicated_detail["workflow"]
|
|
396
|
-
assert duplicated_detail["workflow"]["allow_network"] is True
|
|
397
|
-
assert duplicated_detail["workflow"]["write_dirs"] == ["/tmp"]
|
|
398
|
-
assert {node["name"] for node in duplicated_detail["nodes"]} == {
|
|
399
|
-
"Reviewer",
|
|
400
|
-
"Formatter",
|
|
401
|
-
}
|
|
402
|
-
duplicated_node_ids = {node["id"] for node in duplicated_detail["nodes"]}
|
|
403
|
-
source_node_ids = {node["id"] for node in source_detail["nodes"]}
|
|
404
|
-
assert duplicated_node_ids.isdisjoint(source_node_ids)
|
|
405
|
-
assert duplicated_detail["edges"][0]["from_node_id"] in duplicated_node_ids
|
|
406
|
-
assert duplicated_detail["edges"][0]["to_node_id"] in duplicated_node_ids
|
|
407
|
-
assert duplicated_detail["workflow"]["definition"]["view"]["positions"]
|
|
408
|
-
|
|
409
|
-
|
|
410
320
|
def test_update_tab_definition_updates_metadata_and_positions(client: TestClient):
|
|
411
321
|
tab = client.post(
|
|
412
322
|
"/api/workflows",
|
|
@@ -554,30 +464,6 @@ def test_activate_agent_only_workflow_succeeds_without_trigger(client: TestClien
|
|
|
554
464
|
assert detail["nodes"][0]["id"] == worker["id"]
|
|
555
465
|
|
|
556
466
|
|
|
557
|
-
def test_activate_legacy_agent_only_workflow_succeeds_without_trigger(
|
|
558
|
-
client: TestClient,
|
|
559
|
-
):
|
|
560
|
-
tab = client.post("/api/workflows", json={"title": "Legacy Collaborative"}).json()
|
|
561
|
-
worker = _create_agent_node(client, tab_id=tab["id"], name="Worker")
|
|
562
|
-
definition = deepcopy(
|
|
563
|
-
client.get(f"/api/workflows/{tab['id']}").json()["workflow"]["definition"]
|
|
564
|
-
)
|
|
565
|
-
definition["nodes"][0]["inputs"][0]["required"] = True
|
|
566
|
-
update_response = client.put(
|
|
567
|
-
f"/api/workflows/{tab['id']}/definition",
|
|
568
|
-
json={"definition": definition},
|
|
569
|
-
)
|
|
570
|
-
assert update_response.status_code == 200
|
|
571
|
-
|
|
572
|
-
response = client.post(f"/api/workflows/{tab['id']}/activate")
|
|
573
|
-
|
|
574
|
-
assert response.status_code == 200
|
|
575
|
-
assert response.json()["activation_state"] == "active"
|
|
576
|
-
detail = client.get(f"/api/workflows/{tab['id']}").json()
|
|
577
|
-
assert detail["workflow"]["activation_state"] == "active"
|
|
578
|
-
assert detail["nodes"][0]["id"] == worker["id"]
|
|
579
|
-
|
|
580
|
-
|
|
581
467
|
def test_activate_valid_manual_trigger_graph_succeeds(client: TestClient):
|
|
582
468
|
tab = client.post("/api/workflows", json={"title": "Manual"}).json()
|
|
583
469
|
trigger = _create_graph_node(
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/backend/tests/unit/__pycache__/test_state_sqlite_storage.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
|
Binary file
|
package/backend/tests/unit/agent/__pycache__/test_agent_public_api.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/agent/__pycache__/test_agent_runtime.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
|
@@ -672,11 +672,6 @@ def test_list_roles_tool_returns_registered_roles(monkeypatch):
|
|
|
672
672
|
"fetch",
|
|
673
673
|
"list_roles",
|
|
674
674
|
"list_tools",
|
|
675
|
-
"list_mcp_resources",
|
|
676
|
-
"list_mcp_resource_templates",
|
|
677
|
-
"read_mcp_resource",
|
|
678
|
-
"list_mcp_prompts",
|
|
679
|
-
"get_mcp_prompt",
|
|
680
675
|
],
|
|
681
676
|
},
|
|
682
677
|
{
|
|
@@ -699,11 +694,6 @@ def test_list_roles_tool_returns_registered_roles(monkeypatch):
|
|
|
699
694
|
"exec",
|
|
700
695
|
"list_roles",
|
|
701
696
|
"list_tools",
|
|
702
|
-
"list_mcp_resources",
|
|
703
|
-
"list_mcp_resource_templates",
|
|
704
|
-
"read_mcp_resource",
|
|
705
|
-
"list_mcp_prompts",
|
|
706
|
-
"get_mcp_prompt",
|
|
707
697
|
],
|
|
708
698
|
},
|
|
709
699
|
]
|
|
@@ -735,11 +725,6 @@ def test_list_tools_tool_returns_registered_tool_names_and_descriptions():
|
|
|
735
725
|
"connect",
|
|
736
726
|
"list_roles",
|
|
737
727
|
"list_tools",
|
|
738
|
-
"list_mcp_resources",
|
|
739
|
-
"list_mcp_resource_templates",
|
|
740
|
-
"read_mcp_resource",
|
|
741
|
-
"list_mcp_prompts",
|
|
742
|
-
"get_mcp_prompt",
|
|
743
728
|
}
|
|
744
729
|
assert all(
|
|
745
730
|
{"name", "description", "source", "parameters"} <= set(item) for item in result
|
|
@@ -1118,6 +1118,50 @@ def test_execute_compact_command_replaces_history_with_summary(monkeypatch):
|
|
|
1118
1118
|
assert "Compacted this chat for future replies." not in serialized
|
|
1119
1119
|
|
|
1120
1120
|
|
|
1121
|
+
def test_compacted_context_normalizes_legacy_traceback_summary(monkeypatch):
|
|
1122
|
+
monkeypatch.setattr("flowent.agent.get_settings", lambda: Settings())
|
|
1123
|
+
|
|
1124
|
+
assistant = Agent(NodeConfig(node_type=NodeType.ASSISTANT), uuid="assistant")
|
|
1125
|
+
assistant._set_execution_context(
|
|
1126
|
+
summary=(
|
|
1127
|
+
"## Current Goal\nRecover the chat.\n\n"
|
|
1128
|
+
"Traceback (most recent call last):\n"
|
|
1129
|
+
' File "/tmp/example.py", line 1, in <module>\n'
|
|
1130
|
+
"RuntimeError: boom"
|
|
1131
|
+
),
|
|
1132
|
+
history_cutoff=0,
|
|
1133
|
+
)
|
|
1134
|
+
|
|
1135
|
+
messages = assistant._build_messages()
|
|
1136
|
+
serialized = json.dumps(messages)
|
|
1137
|
+
|
|
1138
|
+
assert "Compacted execution context" in serialized
|
|
1139
|
+
assert "Recover the chat." in serialized
|
|
1140
|
+
assert "Traceback" not in serialized
|
|
1141
|
+
assert "/tmp/example.py" not in serialized
|
|
1142
|
+
|
|
1143
|
+
|
|
1144
|
+
def test_compacted_context_normalizes_legacy_html_summary(monkeypatch):
|
|
1145
|
+
monkeypatch.setattr("flowent.agent.get_settings", lambda: Settings())
|
|
1146
|
+
|
|
1147
|
+
assistant = Agent(NodeConfig(node_type=NodeType.ASSISTANT), uuid="assistant")
|
|
1148
|
+
assistant._set_execution_context(
|
|
1149
|
+
summary=(
|
|
1150
|
+
"## Current Goal\nRecover the chat.\n\n"
|
|
1151
|
+
"<!doctype html><html><body>Bad Gateway</body></html>"
|
|
1152
|
+
),
|
|
1153
|
+
history_cutoff=0,
|
|
1154
|
+
)
|
|
1155
|
+
|
|
1156
|
+
messages = assistant._build_messages()
|
|
1157
|
+
serialized = json.dumps(messages)
|
|
1158
|
+
|
|
1159
|
+
assert "Compacted execution context" in serialized
|
|
1160
|
+
assert "unexpected error response" in serialized
|
|
1161
|
+
assert "<!doctype html" not in serialized
|
|
1162
|
+
assert "<html" not in serialized
|
|
1163
|
+
|
|
1164
|
+
|
|
1121
1165
|
def test_compact_command_excludes_queued_messages_from_summary(monkeypatch):
|
|
1122
1166
|
assistant = Agent(NodeConfig(node_type=NodeType.ASSISTANT), uuid="assistant")
|
|
1123
1167
|
assistant.history.extend(
|
|
@@ -2668,18 +2712,120 @@ def test_build_messages_keeps_error_entries_in_context(monkeypatch):
|
|
|
2668
2712
|
|
|
2669
2713
|
agent = Agent(NodeConfig(node_type=NodeType.AGENT), uuid="agent")
|
|
2670
2714
|
agent._append_history(ReceivedMessage(content="begin", from_id="human"))
|
|
2671
|
-
agent._append_history(ErrorEntry(content="RuntimeError: boom
|
|
2715
|
+
agent._append_history(ErrorEntry(content="RuntimeError: boom"))
|
|
2716
|
+
|
|
2717
|
+
messages = agent._build_messages()
|
|
2718
|
+
|
|
2719
|
+
assert any(
|
|
2720
|
+
msg.get("role") == "user"
|
|
2721
|
+
and msg.get("content")
|
|
2722
|
+
== "<system>Previous runtime error:\nRuntimeError: boom</system>"
|
|
2723
|
+
for msg in messages
|
|
2724
|
+
)
|
|
2725
|
+
|
|
2726
|
+
|
|
2727
|
+
def test_build_messages_normalizes_legacy_traceback_errors(monkeypatch):
|
|
2728
|
+
monkeypatch.setattr("flowent.agent.get_settings", lambda: Settings())
|
|
2729
|
+
|
|
2730
|
+
agent = Agent(NodeConfig(node_type=NodeType.AGENT), uuid="agent")
|
|
2731
|
+
agent._append_history(
|
|
2732
|
+
ErrorEntry(
|
|
2733
|
+
content=(
|
|
2734
|
+
"RuntimeError: boom\n\n"
|
|
2735
|
+
"Traceback (most recent call last):\n"
|
|
2736
|
+
' File "/tmp/example.py", line 1, in <module>\n'
|
|
2737
|
+
"RuntimeError: boom"
|
|
2738
|
+
)
|
|
2739
|
+
)
|
|
2740
|
+
)
|
|
2741
|
+
|
|
2742
|
+
messages = agent._build_messages()
|
|
2743
|
+
|
|
2744
|
+
assert any(
|
|
2745
|
+
msg.get("role") == "user"
|
|
2746
|
+
and msg.get("content")
|
|
2747
|
+
== "<system>Previous runtime error:\nRuntimeError: boom</system>"
|
|
2748
|
+
for msg in messages
|
|
2749
|
+
)
|
|
2750
|
+
assert not any("Traceback" in str(msg.get("content")) for msg in messages)
|
|
2751
|
+
|
|
2752
|
+
|
|
2753
|
+
def test_build_messages_normalizes_legacy_html_errors(monkeypatch):
|
|
2754
|
+
monkeypatch.setattr("flowent.agent.get_settings", lambda: Settings())
|
|
2755
|
+
|
|
2756
|
+
agent = Agent(NodeConfig(node_type=NodeType.AGENT), uuid="agent")
|
|
2757
|
+
agent._append_history(
|
|
2758
|
+
ErrorEntry(content="<html><body><pre>Internal Server Error</pre></body></html>")
|
|
2759
|
+
)
|
|
2760
|
+
|
|
2761
|
+
messages = agent._build_messages()
|
|
2762
|
+
serialized = json.dumps(messages)
|
|
2763
|
+
|
|
2764
|
+
assert "Upstream returned an unexpected error response" in serialized
|
|
2765
|
+
assert "<html" not in serialized
|
|
2766
|
+
assert "<pre>" not in serialized
|
|
2767
|
+
|
|
2768
|
+
|
|
2769
|
+
def test_build_messages_keeps_provider_error_text_in_context(monkeypatch):
|
|
2770
|
+
monkeypatch.setattr("flowent.agent.get_settings", lambda: Settings())
|
|
2771
|
+
|
|
2772
|
+
agent = Agent(NodeConfig(node_type=NodeType.AGENT), uuid="agent")
|
|
2773
|
+
agent._append_history(ErrorEntry(content="LLMProviderError: provider offline"))
|
|
2672
2774
|
|
|
2673
2775
|
messages = agent._build_messages()
|
|
2674
2776
|
|
|
2675
2777
|
assert any(
|
|
2676
2778
|
msg.get("role") == "user"
|
|
2677
2779
|
and msg.get("content")
|
|
2678
|
-
==
|
|
2780
|
+
== (
|
|
2781
|
+
"<system>Previous runtime error:\n"
|
|
2782
|
+
"LLMProviderError: provider offline</system>"
|
|
2783
|
+
)
|
|
2679
2784
|
for msg in messages
|
|
2680
2785
|
)
|
|
2681
2786
|
|
|
2682
2787
|
|
|
2788
|
+
def test_unhandled_runtime_error_history_omits_traceback(monkeypatch):
|
|
2789
|
+
agent = Agent(NodeConfig(node_type=NodeType.AGENT, allow_network=True))
|
|
2790
|
+
wait_calls = 0
|
|
2791
|
+
chat_calls = 0
|
|
2792
|
+
|
|
2793
|
+
def fake_wait_for_input() -> None:
|
|
2794
|
+
nonlocal wait_calls
|
|
2795
|
+
wait_calls += 1
|
|
2796
|
+
if wait_calls == 1:
|
|
2797
|
+
agent._append_history(ReceivedMessage(content="start", from_id="human"))
|
|
2798
|
+
agent.set_state(AgentState.RUNNING, "received message from human")
|
|
2799
|
+
return
|
|
2800
|
+
agent.request_termination("done")
|
|
2801
|
+
|
|
2802
|
+
def fake_chat(
|
|
2803
|
+
messages,
|
|
2804
|
+
tools=None,
|
|
2805
|
+
on_chunk=None,
|
|
2806
|
+
register_interrupt=None,
|
|
2807
|
+
role_name=None,
|
|
2808
|
+
):
|
|
2809
|
+
nonlocal chat_calls
|
|
2810
|
+
chat_calls += 1
|
|
2811
|
+
raise RuntimeError("boom")
|
|
2812
|
+
|
|
2813
|
+
monkeypatch.setattr(agent, "_wait_for_input", fake_wait_for_input)
|
|
2814
|
+
monkeypatch.setattr("flowent.agent.gateway.chat", fake_chat)
|
|
2815
|
+
|
|
2816
|
+
agent._run()
|
|
2817
|
+
|
|
2818
|
+
assert chat_calls == 1
|
|
2819
|
+
assert any(
|
|
2820
|
+
isinstance(entry, ErrorEntry) and entry.content == "RuntimeError: boom"
|
|
2821
|
+
for entry in agent.get_history_snapshot()
|
|
2822
|
+
)
|
|
2823
|
+
assert not any(
|
|
2824
|
+
isinstance(entry, ErrorEntry) and "traceback" in entry.content.lower()
|
|
2825
|
+
for entry in agent.get_history_snapshot()
|
|
2826
|
+
)
|
|
2827
|
+
|
|
2828
|
+
|
|
2683
2829
|
def test_assistant_emits_human_content_for_plain_text_with_target_like_prefix(
|
|
2684
2830
|
monkeypatch,
|
|
2685
2831
|
):
|
package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/backend/tests/unit/providers/__pycache__/test_openai_provider.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/providers/__pycache__/test_openai_responses.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/providers/__pycache__/test_provider_gateway.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/providers/__pycache__/test_think_tag_parser.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/routes/__pycache__/test_prompts_routes.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/routes/__pycache__/test_providers_route.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/routes/__pycache__/test_roles_routes.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
package/backend/tests/unit/routes/__pycache__/test_settings_routes.cpython-313-pytest-9.0.3.pyc
CHANGED
|
Binary file
|
|
@@ -80,25 +80,3 @@ def test_update_prompts_allows_custom_post_prompt_only(monkeypatch):
|
|
|
80
80
|
"custom_prompt": "Keep this.",
|
|
81
81
|
"custom_post_prompt": "Append this after history.",
|
|
82
82
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
def test_update_prompts_accepts_legacy_post_prompt_alias(monkeypatch):
|
|
86
|
-
settings = Settings(custom_prompt="Keep this.", custom_post_prompt="")
|
|
87
|
-
|
|
88
|
-
monkeypatch.setattr("flowent.routes.prompts.get_settings", lambda: settings)
|
|
89
|
-
monkeypatch.setattr("flowent.routes.prompts.save_settings", lambda current: None)
|
|
90
|
-
|
|
91
|
-
result = asyncio.run(
|
|
92
|
-
update_prompts(
|
|
93
|
-
UpdatePromptSettingsRequest.model_validate(
|
|
94
|
-
{"post_prompt": "Append this after history."}
|
|
95
|
-
)
|
|
96
|
-
)
|
|
97
|
-
)
|
|
98
|
-
|
|
99
|
-
assert settings.custom_prompt == "Keep this."
|
|
100
|
-
assert settings.custom_post_prompt == "Append this after history."
|
|
101
|
-
assert result.model_dump() == {
|
|
102
|
-
"custom_prompt": "Keep this.",
|
|
103
|
-
"custom_post_prompt": "Append this after history.",
|
|
104
|
-
}
|