flowent 0.0.7 → 0.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -3
- package/backend/README.md +0 -3
- package/backend/pyproject.toml +2 -8
- package/backend/src/flowent/__init__.py +6 -2
- package/backend/src/flowent/__pycache__/__init__.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/agent.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/context.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/llm.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__/patch.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/paths.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/sandbox.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/storage.cpython-313.pyc +0 -0
- package/backend/src/flowent/__pycache__/tools.cpython-313.pyc +0 -0
- package/backend/src/flowent/agent.py +213 -3173
- package/backend/src/flowent/cli.py +19 -24
- package/backend/src/flowent/context.py +127 -0
- package/backend/src/flowent/llm.py +256 -0
- package/backend/src/flowent/logging.py +170 -129
- package/backend/src/flowent/main.py +321 -70
- package/backend/src/flowent/patch.py +182 -0
- package/backend/src/flowent/paths.py +11 -0
- package/backend/src/flowent/sandbox.py +214 -40
- package/backend/src/flowent/static/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/backend/src/flowent/static/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/backend/src/flowent/static/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/backend/src/flowent/static/assets/index-C76K95ty.js +81 -0
- package/backend/src/flowent/static/assets/index-iUMNKvlU.css +2 -0
- package/backend/src/flowent/static/flowent.png +0 -0
- package/backend/src/flowent/static/index.html +5 -25
- package/backend/src/flowent/storage.py +302 -0
- package/backend/src/flowent/tools.py +376 -0
- package/backend/tests/__pycache__/test_agent_tools.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/__pycache__/test_health.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/__pycache__/test_llm_providers.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/__pycache__/test_persistence.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/__pycache__/test_workspace_chat.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/test_agent_tools.py +477 -0
- package/backend/tests/test_health.py +12 -0
- package/backend/tests/test_llm_providers.py +113 -0
- package/backend/tests/test_logging.py +182 -0
- package/backend/tests/test_persistence.py +125 -0
- package/backend/tests/test_workspace_chat.py +578 -0
- package/backend/uv.lock +803 -99
- package/dist/frontend/assets/geist-cyrillic-wght-normal-CHSlOQsW.woff2 +0 -0
- package/dist/frontend/assets/geist-latin-ext-wght-normal-DMtmJ5ZE.woff2 +0 -0
- package/dist/frontend/assets/geist-latin-wght-normal-Dm3htQBi.woff2 +0 -0
- package/dist/frontend/assets/index-C76K95ty.js +81 -0
- package/dist/frontend/assets/index-iUMNKvlU.css +2 -0
- package/dist/frontend/flowent.png +0 -0
- package/dist/frontend/index.html +5 -25
- package/package.json +1 -2
- 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__/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__/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__/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/access.py +0 -247
- package/backend/src/flowent/assistant_commands.py +0 -115
- package/backend/src/flowent/channels/__init__.py +0 -3
- 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 +0 -615
- package/backend/src/flowent/config.py +0 -14
- package/backend/src/flowent/dev.py +0 -3
- package/backend/src/flowent/events.py +0 -157
- package/backend/src/flowent/graph_runtime.py +0 -60
- package/backend/src/flowent/graph_service.py +0 -2401
- package/backend/src/flowent/image_assets.py +0 -356
- package/backend/src/flowent/model_metadata.py +0 -102
- package/backend/src/flowent/models/__init__.py +0 -125
- 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 +0 -34
- package/backend/src/flowent/models/base.py +0 -24
- package/backend/src/flowent/models/blueprint.py +0 -176
- package/backend/src/flowent/models/content.py +0 -164
- package/backend/src/flowent/models/delta.py +0 -44
- package/backend/src/flowent/models/event.py +0 -51
- package/backend/src/flowent/models/graph.py +0 -472
- package/backend/src/flowent/models/history.py +0 -272
- package/backend/src/flowent/models/llm.py +0 -62
- package/backend/src/flowent/models/message.py +0 -33
- package/backend/src/flowent/models/tab.py +0 -85
- package/backend/src/flowent/models/todo.py +0 -10
- package/backend/src/flowent/network.py +0 -146
- package/backend/src/flowent/observability_service.py +0 -218
- package/backend/src/flowent/prompts/__init__.py +0 -67
- 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 +0 -250
- package/backend/src/flowent/prompts/steward.py +0 -64
- package/backend/src/flowent/providers/__init__.py +0 -23
- 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/anthropic.py +0 -468
- package/backend/src/flowent/providers/base_url.py +0 -60
- package/backend/src/flowent/providers/configuration.py +0 -189
- package/backend/src/flowent/providers/content.py +0 -122
- package/backend/src/flowent/providers/errors.py +0 -223
- package/backend/src/flowent/providers/gateway.py +0 -169
- package/backend/src/flowent/providers/gemini.py +0 -447
- package/backend/src/flowent/providers/headers.py +0 -20
- package/backend/src/flowent/providers/management.py +0 -96
- package/backend/src/flowent/providers/ollama.py +0 -293
- package/backend/src/flowent/providers/openai.py +0 -422
- package/backend/src/flowent/providers/openai_responses.py +0 -655
- package/backend/src/flowent/providers/registry.py +0 -144
- package/backend/src/flowent/providers/sse.py +0 -31
- package/backend/src/flowent/providers/thinking.py +0 -79
- package/backend/src/flowent/registry.py +0 -73
- package/backend/src/flowent/role_management.py +0 -270
- package/backend/src/flowent/routes/__init__.py +0 -26
- 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/access.py +0 -48
- package/backend/src/flowent/routes/assistant.py +0 -158
- package/backend/src/flowent/routes/image_assets.py +0 -33
- package/backend/src/flowent/routes/meta.py +0 -28
- package/backend/src/flowent/routes/nodes.py +0 -423
- package/backend/src/flowent/routes/prompts.py +0 -46
- package/backend/src/flowent/routes/providers_route.py +0 -365
- package/backend/src/flowent/routes/roles.py +0 -207
- package/backend/src/flowent/routes/settings.py +0 -379
- package/backend/src/flowent/routes/tabs.py +0 -298
- package/backend/src/flowent/routes/ws.py +0 -33
- package/backend/src/flowent/runtime.py +0 -160
- package/backend/src/flowent/security.py +0 -37
- package/backend/src/flowent/settings.py +0 -2112
- package/backend/src/flowent/settings_management.py +0 -394
- package/backend/src/flowent/state_db.py +0 -108
- package/backend/src/flowent/static/assets/AssistantPage-BW7XAd9I.js +0 -1
- package/backend/src/flowent/static/assets/ChannelsPage-tCJHgt6m.js +0 -1
- package/backend/src/flowent/static/assets/PageScaffold-f6g2l7XN.js +0 -1
- package/backend/src/flowent/static/assets/PromptsPage-C3Sxn2D7.js +0 -1
- package/backend/src/flowent/static/assets/ProvidersPage-BfmdXmNt.js +0 -3
- package/backend/src/flowent/static/assets/RolesPage-DET8wO4r.js +0 -1
- package/backend/src/flowent/static/assets/SettingsPage-D-g3deMm.js +0 -3
- package/backend/src/flowent/static/assets/ToolsPage-CDmtE2g4.js +0 -1
- package/backend/src/flowent/static/assets/WorkspacePage-AZsJ0sD0.js +0 -3
- package/backend/src/flowent/static/assets/WorkspacePanels-CteCjolX.js +0 -1
- package/backend/src/flowent/static/assets/alert-dialog-Duorp_S-.js +0 -1
- package/backend/src/flowent/static/assets/dialog-C3ixjGjN.js +0 -1
- package/backend/src/flowent/static/assets/elk-worker.min-C9JGDOE-.js +0 -6312
- package/backend/src/flowent/static/assets/graph-vendor-CHpVij2M.css +0 -1
- package/backend/src/flowent/static/assets/graph-vendor-DRq_-6fV.js +0 -7
- package/backend/src/flowent/static/assets/index--o_0fv0N.css +0 -1
- package/backend/src/flowent/static/assets/index-C9HuekJm.js +0 -10
- package/backend/src/flowent/static/assets/layout.worker-jMHqAFbP.js +0 -24
- package/backend/src/flowent/static/assets/markdown-vendor-C9RtvaJh.js +0 -29
- package/backend/src/flowent/static/assets/modelParams-DmnF2hwR.js +0 -1
- package/backend/src/flowent/static/assets/providerTypes-DT3Ahwl_.js +0 -1
- package/backend/src/flowent/static/assets/react-vendor-mEs_JJxa.js +0 -9
- package/backend/src/flowent/static/assets/roles-CuRT_chR.js +0 -1
- package/backend/src/flowent/static/assets/rolldown-runtime-BYbx6iT9.js +0 -1
- package/backend/src/flowent/static/assets/select-DCfeNu-F.js +0 -1
- package/backend/src/flowent/static/assets/surface-pWwG5ogx.js +0 -1
- package/backend/src/flowent/static/assets/ui-vendor-C5pJa8N7.js +0 -51
- package/backend/src/flowent/static/assets/useAppRoute-FgSHBKhV.js +0 -1
- package/backend/src/flowent/static/favicon.svg +0 -4
- package/backend/src/flowent/tools/__init__.py +0 -176
- 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/connect.py +0 -100
- package/backend/src/flowent/tools/contacts.py +0 -22
- package/backend/src/flowent/tools/create_agent.py +0 -191
- package/backend/src/flowent/tools/create_tab.py +0 -61
- package/backend/src/flowent/tools/delete_tab.py +0 -39
- package/backend/src/flowent/tools/edit.py +0 -142
- package/backend/src/flowent/tools/exec.py +0 -118
- package/backend/src/flowent/tools/fetch.py +0 -85
- package/backend/src/flowent/tools/idle.py +0 -27
- package/backend/src/flowent/tools/list_roles.py +0 -68
- package/backend/src/flowent/tools/list_tabs.py +0 -100
- package/backend/src/flowent/tools/list_tools.py +0 -28
- package/backend/src/flowent/tools/manage_prompts.py +0 -102
- package/backend/src/flowent/tools/manage_providers.py +0 -220
- package/backend/src/flowent/tools/manage_roles.py +0 -275
- package/backend/src/flowent/tools/manage_settings.py +0 -326
- package/backend/src/flowent/tools/read.py +0 -152
- package/backend/src/flowent/tools/send.py +0 -68
- package/backend/src/flowent/tools/set_permissions.py +0 -99
- package/backend/src/flowent/tools/sleep.py +0 -41
- package/backend/src/flowent/tools/todo.py +0 -51
- package/backend/src/flowent/workspace_store.py +0 -479
- package/backend/tests/__init__.py +0 -0
- 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/conftest.py +0 -6
- 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/conftest.py +0 -29
- package/backend/tests/integration/api/test_access_api.py +0 -182
- package/backend/tests/integration/api/test_assistant_api.py +0 -422
- package/backend/tests/integration/api/test_frontend_mounting.py +0 -61
- package/backend/tests/integration/api/test_meta_api.py +0 -32
- package/backend/tests/integration/api/test_nodes_api.py +0 -787
- package/backend/tests/integration/api/test_prompts_api.py +0 -47
- package/backend/tests/integration/api/test_roles_api.py +0 -228
- package/backend/tests/integration/api/test_tabs_api.py +0 -688
- 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 -822
- package/backend/tests/unit/agent/test_agent_runtime.py +0 -3088
- package/backend/tests/unit/channels/__pycache__/test_telegram_channel.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/channels/test_telegram_channel.py +0 -552
- package/backend/tests/unit/logging/__pycache__/test_logging.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/logging/test_logging.py +0 -132
- 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 +0 -570
- 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/providers/test_anthropic_provider.py +0 -185
- package/backend/tests/unit/providers/test_errors.py +0 -68
- package/backend/tests/unit/providers/test_extract_delta_parts.py +0 -22
- package/backend/tests/unit/providers/test_openai_provider.py +0 -139
- package/backend/tests/unit/providers/test_openai_responses.py +0 -402
- package/backend/tests/unit/providers/test_provider_gateway.py +0 -359
- package/backend/tests/unit/providers/test_think_tag_parser.py +0 -36
- 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 -82
- package/backend/tests/unit/routes/test_providers_route.py +0 -370
- package/backend/tests/unit/routes/test_roles_routes.py +0 -539
- package/backend/tests/unit/routes/test_settings_routes.py +0 -1123
- 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 +0 -1002
- package/backend/tests/unit/sandbox/__pycache__/test_sandbox_tools.cpython-313-pytest-9.0.3.pyc +0 -0
- package/backend/tests/unit/sandbox/test_sandbox_tools.py +0 -78
- 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 +0 -124
- 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 +0 -703
- package/backend/tests/unit/test_access.py +0 -45
- package/backend/tests/unit/test_cli.py +0 -102
- package/backend/tests/unit/test_graph_runtime.py +0 -72
- package/backend/tests/unit/test_network.py +0 -51
- package/backend/tests/unit/test_state_sqlite_storage.py +0 -87
- package/backend/tests/unit/test_workspace_store.py +0 -228
- 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 +0 -228
- package/backend/tests/unit/tools/test_create_agent_tool.py +0 -404
- package/backend/tests/unit/tools/test_delete_tab_tool.py +0 -116
- package/backend/tests/unit/tools/test_edit_tool.py +0 -115
- package/backend/tests/unit/tools/test_exec_tool.py +0 -81
- package/backend/tests/unit/tools/test_fetch_tool.py +0 -65
- package/backend/tests/unit/tools/test_manage_prompts_tool.py +0 -92
- package/backend/tests/unit/tools/test_manage_providers_tool.py +0 -460
- package/backend/tests/unit/tools/test_manage_roles_tool.py +0 -411
- package/backend/tests/unit/tools/test_manage_settings_tool.py +0 -611
- package/backend/tests/unit/tools/test_read_tool.py +0 -33
- package/backend/tests/unit/tools/test_set_permissions_tool.py +0 -595
- package/backend/tests/unit/tools/test_todo_tool.py +0 -37
- package/backend/tests/unit/tools/test_tool_registry.py +0 -199
- package/dist/frontend/assets/AssistantPage-BW7XAd9I.js +0 -1
- package/dist/frontend/assets/ChannelsPage-tCJHgt6m.js +0 -1
- package/dist/frontend/assets/PageScaffold-f6g2l7XN.js +0 -1
- package/dist/frontend/assets/PromptsPage-C3Sxn2D7.js +0 -1
- package/dist/frontend/assets/ProvidersPage-BfmdXmNt.js +0 -3
- package/dist/frontend/assets/RolesPage-DET8wO4r.js +0 -1
- package/dist/frontend/assets/SettingsPage-D-g3deMm.js +0 -3
- package/dist/frontend/assets/ToolsPage-CDmtE2g4.js +0 -1
- package/dist/frontend/assets/WorkspacePage-AZsJ0sD0.js +0 -3
- package/dist/frontend/assets/WorkspacePanels-CteCjolX.js +0 -1
- package/dist/frontend/assets/alert-dialog-Duorp_S-.js +0 -1
- package/dist/frontend/assets/dialog-C3ixjGjN.js +0 -1
- package/dist/frontend/assets/elk-worker.min-C9JGDOE-.js +0 -6312
- package/dist/frontend/assets/graph-vendor-CHpVij2M.css +0 -1
- package/dist/frontend/assets/graph-vendor-DRq_-6fV.js +0 -7
- package/dist/frontend/assets/index--o_0fv0N.css +0 -1
- package/dist/frontend/assets/index-C9HuekJm.js +0 -10
- package/dist/frontend/assets/layout.worker-jMHqAFbP.js +0 -24
- package/dist/frontend/assets/markdown-vendor-C9RtvaJh.js +0 -29
- package/dist/frontend/assets/modelParams-DmnF2hwR.js +0 -1
- package/dist/frontend/assets/providerTypes-DT3Ahwl_.js +0 -1
- package/dist/frontend/assets/react-vendor-mEs_JJxa.js +0 -9
- package/dist/frontend/assets/roles-CuRT_chR.js +0 -1
- package/dist/frontend/assets/rolldown-runtime-BYbx6iT9.js +0 -1
- package/dist/frontend/assets/select-DCfeNu-F.js +0 -1
- package/dist/frontend/assets/surface-pWwG5ogx.js +0 -1
- package/dist/frontend/assets/ui-vendor-C5pJa8N7.js +0 -51
- package/dist/frontend/assets/useAppRoute-FgSHBKhV.js +0 -1
- package/dist/frontend/favicon.svg +0 -4
|
@@ -0,0 +1,376 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import subprocess
|
|
5
|
+
import sys
|
|
6
|
+
import urllib.parse
|
|
7
|
+
import urllib.request
|
|
8
|
+
from collections.abc import Callable, Sequence
|
|
9
|
+
from dataclasses import dataclass
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from uuid import uuid4
|
|
12
|
+
|
|
13
|
+
from pydantic import BaseModel, ConfigDict
|
|
14
|
+
|
|
15
|
+
from flowent.patch import affected_paths
|
|
16
|
+
from flowent.sandbox import SandboxError, SandboxRunner
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class ToolResult(BaseModel):
|
|
20
|
+
model_config = ConfigDict(extra="forbid")
|
|
21
|
+
|
|
22
|
+
content: str
|
|
23
|
+
data: dict[str, object] = {}
|
|
24
|
+
ok: bool = True
|
|
25
|
+
title: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@dataclass(frozen=True)
|
|
29
|
+
class ToolContext:
|
|
30
|
+
cwd: Path
|
|
31
|
+
web_searcher: Callable[[str], Sequence[dict[str, str]]] | None = None
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def tool_specs() -> list[dict[str, object]]:
|
|
35
|
+
return [
|
|
36
|
+
{
|
|
37
|
+
"type": "function",
|
|
38
|
+
"function": {
|
|
39
|
+
"name": "read_file",
|
|
40
|
+
"description": "Read text from a file.",
|
|
41
|
+
"parameters": {
|
|
42
|
+
"type": "object",
|
|
43
|
+
"properties": {
|
|
44
|
+
"path": {"type": "string"},
|
|
45
|
+
"offset": {"type": "integer", "minimum": 0},
|
|
46
|
+
"limit": {"type": "integer", "minimum": 1},
|
|
47
|
+
},
|
|
48
|
+
"required": ["path"],
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"type": "function",
|
|
54
|
+
"function": {
|
|
55
|
+
"name": "list_dir",
|
|
56
|
+
"description": "List directory entries.",
|
|
57
|
+
"parameters": {
|
|
58
|
+
"type": "object",
|
|
59
|
+
"properties": {
|
|
60
|
+
"path": {"type": "string"},
|
|
61
|
+
"limit": {"type": "integer", "minimum": 1},
|
|
62
|
+
},
|
|
63
|
+
"required": ["path"],
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"type": "function",
|
|
69
|
+
"function": {
|
|
70
|
+
"name": "grep_files",
|
|
71
|
+
"description": "Search file contents.",
|
|
72
|
+
"parameters": {
|
|
73
|
+
"type": "object",
|
|
74
|
+
"properties": {
|
|
75
|
+
"pattern": {"type": "string"},
|
|
76
|
+
"path": {"type": "string"},
|
|
77
|
+
"include": {"type": "string"},
|
|
78
|
+
"limit": {"type": "integer", "minimum": 1},
|
|
79
|
+
},
|
|
80
|
+
"required": ["pattern"],
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
"type": "function",
|
|
86
|
+
"function": {
|
|
87
|
+
"name": "apply_patch",
|
|
88
|
+
"description": "Apply a structured patch to files.",
|
|
89
|
+
"parameters": {
|
|
90
|
+
"type": "object",
|
|
91
|
+
"properties": {"patch": {"type": "string"}},
|
|
92
|
+
"required": ["patch"],
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"type": "function",
|
|
98
|
+
"function": {
|
|
99
|
+
"name": "shell_command",
|
|
100
|
+
"description": "Run a shell command.",
|
|
101
|
+
"parameters": {
|
|
102
|
+
"type": "object",
|
|
103
|
+
"properties": {
|
|
104
|
+
"command": {"type": "string"},
|
|
105
|
+
"timeout_seconds": {"type": "integer", "minimum": 1},
|
|
106
|
+
},
|
|
107
|
+
"required": ["command"],
|
|
108
|
+
},
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
"type": "function",
|
|
113
|
+
"function": {
|
|
114
|
+
"name": "update_plan",
|
|
115
|
+
"description": "Record current task plan items.",
|
|
116
|
+
"parameters": {
|
|
117
|
+
"type": "object",
|
|
118
|
+
"properties": {
|
|
119
|
+
"items": {
|
|
120
|
+
"type": "array",
|
|
121
|
+
"items": {
|
|
122
|
+
"type": "object",
|
|
123
|
+
"properties": {
|
|
124
|
+
"step": {"type": "string"},
|
|
125
|
+
"status": {"type": "string"},
|
|
126
|
+
},
|
|
127
|
+
"required": ["step", "status"],
|
|
128
|
+
},
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
"required": ["items"],
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"type": "function",
|
|
137
|
+
"function": {
|
|
138
|
+
"name": "web_search",
|
|
139
|
+
"description": "Search the web for current information.",
|
|
140
|
+
"parameters": {
|
|
141
|
+
"type": "object",
|
|
142
|
+
"properties": {"query": {"type": "string"}},
|
|
143
|
+
"required": ["query"],
|
|
144
|
+
},
|
|
145
|
+
},
|
|
146
|
+
},
|
|
147
|
+
]
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def resolve_tool_path(raw_path: str, cwd: Path) -> Path:
|
|
151
|
+
path = Path(raw_path).expanduser()
|
|
152
|
+
if not path.is_absolute():
|
|
153
|
+
path = cwd / path
|
|
154
|
+
return path.resolve(strict=False)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def tool_call_title(name: str, arguments: dict[str, object]) -> str:
|
|
158
|
+
if name == "read_file":
|
|
159
|
+
return f"Reading {arguments.get('path', 'file')}"
|
|
160
|
+
if name == "list_dir":
|
|
161
|
+
return f"Listing {arguments.get('path', 'directory')}"
|
|
162
|
+
if name == "grep_files":
|
|
163
|
+
return f"Searching {arguments.get('pattern', 'files')}"
|
|
164
|
+
if name == "apply_patch":
|
|
165
|
+
return "Applying patch"
|
|
166
|
+
if name == "shell_command":
|
|
167
|
+
return f"Running {arguments.get('command', 'command')}"
|
|
168
|
+
if name == "update_plan":
|
|
169
|
+
return "Updating plan"
|
|
170
|
+
if name == "web_search":
|
|
171
|
+
return f"Searching web for {arguments.get('query', '')}"
|
|
172
|
+
return name
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def run_tool(
|
|
176
|
+
name: str, arguments: dict[str, object], context: ToolContext
|
|
177
|
+
) -> ToolResult:
|
|
178
|
+
try:
|
|
179
|
+
if name == "read_file":
|
|
180
|
+
return read_file(arguments, context)
|
|
181
|
+
if name == "list_dir":
|
|
182
|
+
return list_dir(arguments, context)
|
|
183
|
+
if name == "grep_files":
|
|
184
|
+
return grep_files(arguments, context)
|
|
185
|
+
if name == "apply_patch":
|
|
186
|
+
return apply_patch_tool(arguments, context)
|
|
187
|
+
if name == "shell_command":
|
|
188
|
+
return shell_command(arguments, context)
|
|
189
|
+
if name == "update_plan":
|
|
190
|
+
return update_plan(arguments)
|
|
191
|
+
if name == "web_search":
|
|
192
|
+
return web_search(arguments, context)
|
|
193
|
+
raise ValueError("Tool is not available.")
|
|
194
|
+
except Exception as error:
|
|
195
|
+
return ToolResult(
|
|
196
|
+
content=str(error), ok=False, title=tool_call_title(name, arguments)
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def integer_argument(arguments: dict[str, object], name: str, default: int) -> int:
|
|
201
|
+
value = arguments.get(name, default)
|
|
202
|
+
if isinstance(value, int):
|
|
203
|
+
return value
|
|
204
|
+
if isinstance(value, str):
|
|
205
|
+
return int(value)
|
|
206
|
+
return default
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def read_file(arguments: dict[str, object], context: ToolContext) -> ToolResult:
|
|
210
|
+
path = resolve_tool_path(str(arguments["path"]), context.cwd)
|
|
211
|
+
offset = integer_argument(arguments, "offset", 0)
|
|
212
|
+
limit = integer_argument(arguments, "limit", 200)
|
|
213
|
+
lines = path.read_text(errors="replace").splitlines()
|
|
214
|
+
selected = lines[offset : offset + limit]
|
|
215
|
+
content = "\n".join(selected)
|
|
216
|
+
return ToolResult(content=content, data={"path": str(path)}, title=f"Read {path}")
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
def list_dir(arguments: dict[str, object], context: ToolContext) -> ToolResult:
|
|
220
|
+
path = resolve_tool_path(str(arguments["path"]), context.cwd)
|
|
221
|
+
limit = integer_argument(arguments, "limit", 200)
|
|
222
|
+
entries = sorted(
|
|
223
|
+
path.iterdir(), key=lambda item: (not item.is_dir(), item.name.lower())
|
|
224
|
+
)
|
|
225
|
+
rendered = [
|
|
226
|
+
f"{entry.name}/" if entry.is_dir() else entry.name for entry in entries[:limit]
|
|
227
|
+
]
|
|
228
|
+
return ToolResult(
|
|
229
|
+
content="\n".join(rendered), data={"path": str(path)}, title=f"Listed {path}"
|
|
230
|
+
)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
def grep_files(arguments: dict[str, object], context: ToolContext) -> ToolResult:
|
|
234
|
+
pattern = str(arguments["pattern"])
|
|
235
|
+
path = resolve_tool_path(str(arguments.get("path", ".") or "."), context.cwd)
|
|
236
|
+
limit = integer_argument(arguments, "limit", 100)
|
|
237
|
+
command = ["rg", "--line-number", "--max-count", str(limit)]
|
|
238
|
+
include = arguments.get("include")
|
|
239
|
+
if include:
|
|
240
|
+
command.extend(["--glob", str(include)])
|
|
241
|
+
command.extend([pattern, str(path)])
|
|
242
|
+
completed = subprocess.run(
|
|
243
|
+
command, check=False, capture_output=True, text=True, timeout=15
|
|
244
|
+
)
|
|
245
|
+
output = completed.stdout or completed.stderr
|
|
246
|
+
return ToolResult(
|
|
247
|
+
content=output[:20000],
|
|
248
|
+
data={"path": str(path), "pattern": pattern},
|
|
249
|
+
title=f"Searched {pattern}",
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
def apply_patch_tool(arguments: dict[str, object], context: ToolContext) -> ToolResult:
|
|
254
|
+
patch = str(arguments["patch"])
|
|
255
|
+
paths = affected_paths(patch, context.cwd)
|
|
256
|
+
runner = SandboxRunner(cwd=context.cwd)
|
|
257
|
+
for path in paths:
|
|
258
|
+
runner.ensure_writable_path(path)
|
|
259
|
+
result = runner.run(
|
|
260
|
+
[sys.executable, "-m", "flowent.cli", "apply-patch", "--cwd", str(context.cwd)],
|
|
261
|
+
input_text=patch,
|
|
262
|
+
)
|
|
263
|
+
if result.exit_code != 0:
|
|
264
|
+
raise SandboxError(tool_failure_content(result))
|
|
265
|
+
return ToolResult(
|
|
266
|
+
content=result.stdout,
|
|
267
|
+
data={"files": [str(path) for path in paths]},
|
|
268
|
+
title="Applied patch",
|
|
269
|
+
)
|
|
270
|
+
|
|
271
|
+
|
|
272
|
+
def tool_failure_content(result: object) -> str:
|
|
273
|
+
stdout = str(getattr(result, "stdout", "") or "").strip()
|
|
274
|
+
stderr = str(getattr(result, "stderr", "") or "").strip()
|
|
275
|
+
if stdout:
|
|
276
|
+
try:
|
|
277
|
+
payload = json.loads(stdout)
|
|
278
|
+
except json.JSONDecodeError:
|
|
279
|
+
payload = None
|
|
280
|
+
if isinstance(payload, dict) and isinstance(payload.get("error"), str):
|
|
281
|
+
return payload["error"]
|
|
282
|
+
parts = [part for part in [stderr, stdout] if part]
|
|
283
|
+
return "\n".join(parts) or "Tool failed."
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
def shell_command(arguments: dict[str, object], context: ToolContext) -> ToolResult:
|
|
287
|
+
command = str(arguments["command"])
|
|
288
|
+
timeout_seconds = integer_argument(arguments, "timeout_seconds", 30)
|
|
289
|
+
result = SandboxRunner(cwd=context.cwd).run(
|
|
290
|
+
["/bin/sh", "-c", command], timeout_seconds=timeout_seconds
|
|
291
|
+
)
|
|
292
|
+
ok = result.exit_code == 0
|
|
293
|
+
content = result.stdout or result.stderr
|
|
294
|
+
return ToolResult(
|
|
295
|
+
content=content,
|
|
296
|
+
data={
|
|
297
|
+
"command": command,
|
|
298
|
+
"exit_code": result.exit_code,
|
|
299
|
+
"stderr": result.stderr,
|
|
300
|
+
"stdout": result.stdout,
|
|
301
|
+
},
|
|
302
|
+
ok=ok,
|
|
303
|
+
title=f"Ran {command}",
|
|
304
|
+
)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
def update_plan(arguments: dict[str, object]) -> ToolResult:
|
|
308
|
+
items = arguments.get("items", [])
|
|
309
|
+
content = json.dumps(items, ensure_ascii=False)
|
|
310
|
+
return ToolResult(
|
|
311
|
+
content=content,
|
|
312
|
+
data={"items": items if isinstance(items, list) else []},
|
|
313
|
+
title="Updated plan",
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
def default_web_search(query: str) -> list[dict[str, str]]:
|
|
318
|
+
encoded_query = urllib.parse.urlencode({"q": query})
|
|
319
|
+
request = urllib.request.Request(
|
|
320
|
+
f"https://duckduckgo.com/html/?{encoded_query}",
|
|
321
|
+
headers={"User-Agent": "Flowent/0.1"},
|
|
322
|
+
)
|
|
323
|
+
with urllib.request.urlopen(request, timeout=10) as response:
|
|
324
|
+
body = response.read().decode(errors="replace")
|
|
325
|
+
results: list[dict[str, str]] = []
|
|
326
|
+
for marker in body.split('class="result__a"')[1:6]:
|
|
327
|
+
href_marker = 'href="'
|
|
328
|
+
href_start = marker.find(href_marker)
|
|
329
|
+
title_start = marker.find(">", href_start)
|
|
330
|
+
title_end = marker.find("</a>", title_start)
|
|
331
|
+
if href_start == -1 or title_start == -1 or title_end == -1:
|
|
332
|
+
continue
|
|
333
|
+
href = marker[
|
|
334
|
+
href_start + len(href_marker) : marker.find(
|
|
335
|
+
'"', href_start + len(href_marker)
|
|
336
|
+
)
|
|
337
|
+
]
|
|
338
|
+
title = marker[title_start + 1 : title_end]
|
|
339
|
+
results.append({"title": title, "url": href, "snippet": ""})
|
|
340
|
+
return results
|
|
341
|
+
|
|
342
|
+
|
|
343
|
+
def web_search(arguments: dict[str, object], context: ToolContext) -> ToolResult:
|
|
344
|
+
query = str(arguments["query"])
|
|
345
|
+
if context.web_searcher is not None:
|
|
346
|
+
results = list(context.web_searcher(query))
|
|
347
|
+
else:
|
|
348
|
+
results = default_web_search(query)
|
|
349
|
+
content = "\n".join(
|
|
350
|
+
f"{result.get('title', '')}: {result.get('url', '')} {result.get('snippet', '')}"
|
|
351
|
+
for result in results
|
|
352
|
+
)
|
|
353
|
+
return ToolResult(
|
|
354
|
+
content=content or "No results.",
|
|
355
|
+
data={"query": query, "results": results},
|
|
356
|
+
title=f"Searched web for {query}",
|
|
357
|
+
)
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
def parse_tool_arguments(arguments: str) -> dict[str, object]:
|
|
361
|
+
if not arguments.strip():
|
|
362
|
+
return {}
|
|
363
|
+
parsed = json.loads(arguments)
|
|
364
|
+
if not isinstance(parsed, dict):
|
|
365
|
+
raise ValueError("Tool arguments must be an object.")
|
|
366
|
+
return parsed
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
def new_tool_item(name: str, arguments: dict[str, object]) -> dict[str, object]:
|
|
370
|
+
return {
|
|
371
|
+
"id": str(uuid4()),
|
|
372
|
+
"arguments": arguments,
|
|
373
|
+
"name": name,
|
|
374
|
+
"status": "running",
|
|
375
|
+
"title": tool_call_title(name, arguments),
|
|
376
|
+
}
|