solace-agent-mesh 1.6.2__py3-none-any.whl → 1.7.0__py3-none-any.whl
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.
Potentially problematic release.
This version of solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agent/adk/adk_llm.txt +12 -18
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
- solace_agent_mesh/agent/adk/callbacks.py +138 -20
- solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +2 -0
- solace_agent_mesh/agent/adk/models/lite_llm.py +38 -5
- solace_agent_mesh/agent/adk/models/models_llm.txt +82 -35
- solace_agent_mesh/agent/adk/runner.py +9 -0
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/adk/stream_parser.py +6 -1
- solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
- solace_agent_mesh/agent/agent_llm.txt +61 -70
- solace_agent_mesh/agent/protocol/event_handlers.py +29 -1
- solace_agent_mesh/agent/protocol/protocol_llm.txt +1 -1
- solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +190 -0
- solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
- solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
- solace_agent_mesh/agent/sac/app.py +22 -0
- solace_agent_mesh/agent/sac/component.py +76 -40
- solace_agent_mesh/agent/sac/sac_llm.txt +1 -1
- solace_agent_mesh/agent/sac/task_execution_context.py +21 -0
- solace_agent_mesh/agent/testing/testing_llm.txt +2 -1
- solace_agent_mesh/agent/tools/builtin_artifact_tools.py +13 -148
- solace_agent_mesh/agent/tools/dynamic_tool.py +2 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +93 -80
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +3 -2
- solace_agent_mesh/agent/utils/artifact_helpers.py +4 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +16 -2
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{ab9708a8.3e6dd091.js → ab9708a8.245ae0ef.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{e6f9706b.e74a984d.js → e6f9706b.045d0fa1.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.e6488e8b.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +18 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +196 -0
- solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +6 -7
- solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +47 -0
- solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +160 -169
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +59 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +62 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +10 -6
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +24 -29
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +27 -4
- solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +5 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +290 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
- solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
- solace_agent_mesh/assets/docs/lunr-index-1762189824009.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1762189824009.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/assets/docs/sitemap.xml +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/docs_cmd.py +4 -1
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-D4_RMYRh.js → authCallback-tcIFZLis.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-UZ3qU6Bq.js → client-CRYdKo2Q.js} +3 -3
- solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +353 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-CINwxvwV.js +470 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/common/a2a/a2a_llm.txt +13 -20
- solace_agent_mesh/common/a2a/protocol.py +5 -0
- solace_agent_mesh/common/a2a/types.py +1 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +49 -11
- solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
- solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +26 -9
- solace_agent_mesh/common/common_llm.txt +13 -34
- solace_agent_mesh/common/data_parts.py +20 -4
- solace_agent_mesh/common/middleware/middleware_llm.txt +1 -1
- solace_agent_mesh/common/sac/sac_llm.txt +1 -1
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +1 -1
- solace_agent_mesh/common/services/employee_service.py +1 -1
- solace_agent_mesh/common/services/providers/providers_llm.txt +3 -2
- solace_agent_mesh/common/services/services_llm.txt +9 -4
- solace_agent_mesh/common/utils/embeds/constants.py +1 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
- solace_agent_mesh/common/utils/embeds/modifiers.py +2 -1
- solace_agent_mesh/common/utils/embeds/resolver.py +58 -6
- solace_agent_mesh/common/utils/embeds/types.py +8 -0
- solace_agent_mesh/common/utils/utils_llm.txt +5 -6
- solace_agent_mesh/core_a2a/core_a2a_llm.txt +1 -1
- solace_agent_mesh/gateway/adapter/__init__.py +1 -0
- solace_agent_mesh/gateway/adapter/base.py +143 -0
- solace_agent_mesh/gateway/adapter/types.py +221 -0
- solace_agent_mesh/gateway/base/app.py +29 -2
- solace_agent_mesh/gateway/base/base_llm.txt +10 -8
- solace_agent_mesh/gateway/base/component.py +573 -142
- solace_agent_mesh/gateway/gateway_llm.txt +55 -59
- solace_agent_mesh/gateway/generic/__init__.py +1 -0
- solace_agent_mesh/gateway/generic/app.py +50 -0
- solace_agent_mesh/gateway/generic/component.py +650 -0
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +99 -49
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +92 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +150 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +26 -20
- solace_agent_mesh/gateway/http_sse/app.py +19 -14
- solace_agent_mesh/gateway/http_sse/component.py +150 -118
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +1 -1
- solace_agent_mesh/gateway/http_sse/dependencies.py +21 -3
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +8 -8
- solace_agent_mesh/gateway/http_sse/main.py +55 -14
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +56 -98
- solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +23 -1
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +112 -4
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -1
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +51 -60
- solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
- solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +7 -1
- solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
- solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +125 -157
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +269 -8
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +143 -51
- solace_agent_mesh/gateway/http_sse/routers/config.py +69 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +198 -94
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +68 -18
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +13 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +30 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +51 -35
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +2 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
- solace_agent_mesh/gateway/http_sse/routers/projects.py +542 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +9 -11
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +154 -3
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +296 -4
- solace_agent_mesh/gateway/http_sse/services/project_service.py +403 -0
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +16 -10
- solace_agent_mesh/gateway/http_sse/services/session_service.py +178 -6
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +2 -3
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +48 -14
- solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
- {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/METADATA +3 -5
- {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/RECORD +219 -176
- solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/631738c7.7c4594c9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/71da7b71.ddbdfbe2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/e92d0134.4f395c6b.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.720d2ef2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.d1643f0b.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.97f920d4.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1761663789856.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1761663789856.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main--3yJYl7S.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-DojKHS49.js +0 -342
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-DSqhjwq_.js +0 -405
- /solace_agent_mesh/assets/docs/assets/js/{main.d1643f0b.js.LICENSE.txt → main.e6488e8b.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,9 +1,14 @@
|
|
|
1
1
|
import logging
|
|
2
2
|
import os
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import TYPE_CHECKING
|
|
5
4
|
|
|
6
5
|
import httpx
|
|
6
|
+
import sqlalchemy as sa
|
|
7
|
+
from fastapi import FastAPI, HTTPException
|
|
8
|
+
from fastapi import Request as FastAPIRequest
|
|
9
|
+
from fastapi import status
|
|
10
|
+
from typing import TYPE_CHECKING
|
|
11
|
+
|
|
7
12
|
import sqlalchemy as sa
|
|
8
13
|
from a2a.types import InternalError, JSONRPCError
|
|
9
14
|
from a2a.types import JSONRPCResponse as A2AJSONRPCResponse
|
|
@@ -18,23 +23,35 @@ from fastapi.responses import JSONResponse
|
|
|
18
23
|
from starlette.middleware.sessions import SessionMiddleware
|
|
19
24
|
from starlette.staticfiles import StaticFiles
|
|
20
25
|
|
|
26
|
+
from .routers.sessions import router as session_router
|
|
27
|
+
from .routers.tasks import router as task_router
|
|
28
|
+
from .routers.users import router as user_router
|
|
21
29
|
from ...common import a2a
|
|
22
30
|
from ...gateway.http_sse import dependencies
|
|
23
|
-
from
|
|
31
|
+
from .routers import (
|
|
24
32
|
agent_cards,
|
|
25
33
|
artifacts,
|
|
26
34
|
auth,
|
|
27
35
|
config,
|
|
36
|
+
feedback,
|
|
28
37
|
people,
|
|
29
38
|
sse,
|
|
30
|
-
tasks,
|
|
31
39
|
visualization,
|
|
32
|
-
|
|
40
|
+
projects,
|
|
33
41
|
)
|
|
34
42
|
from .routers.sessions import router as session_router
|
|
35
43
|
from .routers.tasks import router as task_router
|
|
36
44
|
from .routers.users import router as user_router
|
|
37
45
|
|
|
46
|
+
from alembic import command
|
|
47
|
+
from alembic.config import Config
|
|
48
|
+
|
|
49
|
+
from a2a.types import InternalError, InvalidRequestError, JSONRPCError
|
|
50
|
+
from a2a.types import JSONRPCResponse as A2AJSONRPCResponse
|
|
51
|
+
from ...common import a2a
|
|
52
|
+
from ...gateway.http_sse import dependencies
|
|
53
|
+
|
|
54
|
+
|
|
38
55
|
if TYPE_CHECKING:
|
|
39
56
|
from gateway.http_sse.component import WebUIBackendComponent
|
|
40
57
|
|
|
@@ -453,17 +470,32 @@ def _run_enterprise_migrations(
|
|
|
453
470
|
raise RuntimeError(f"Enterprise database migration failed: {e}") from e
|
|
454
471
|
|
|
455
472
|
|
|
456
|
-
def _setup_database(
|
|
473
|
+
def _setup_database(
|
|
474
|
+
component: "WebUIBackendComponent",
|
|
475
|
+
database_url: str,
|
|
476
|
+
platform_database_url: str = None
|
|
477
|
+
) -> None:
|
|
457
478
|
"""
|
|
458
|
-
Initialize database
|
|
459
|
-
|
|
479
|
+
Initialize database connections and run all required migrations.
|
|
480
|
+
Sets up both runtime and platform database schemas.
|
|
481
|
+
|
|
482
|
+
Args:
|
|
483
|
+
component: WebUIBackendComponent instance
|
|
484
|
+
database_url: Runtime database URL (sessions, tasks, chat) - REQUIRED
|
|
485
|
+
platform_database_url: Platform database URL (agents, connectors, deployments).
|
|
486
|
+
If None, platform features will be unavailable.
|
|
460
487
|
"""
|
|
461
488
|
dependencies.init_database(database_url)
|
|
462
489
|
log.info("Persistence enabled - sessions will be stored in database")
|
|
463
490
|
log.info("Running database migrations...")
|
|
464
491
|
|
|
465
492
|
_run_community_migrations(database_url)
|
|
466
|
-
|
|
493
|
+
|
|
494
|
+
if platform_database_url:
|
|
495
|
+
log.info("Platform database configured - running migrations")
|
|
496
|
+
_run_enterprise_migrations(component, platform_database_url)
|
|
497
|
+
else:
|
|
498
|
+
log.info("No platform database configured - skipping platform migrations")
|
|
467
499
|
|
|
468
500
|
|
|
469
501
|
def _get_app_config(component: "WebUIBackendComponent") -> dict:
|
|
@@ -498,12 +530,20 @@ def _create_api_config(app_config: dict, database_url: str) -> dict:
|
|
|
498
530
|
}
|
|
499
531
|
|
|
500
532
|
|
|
501
|
-
def setup_dependencies(
|
|
533
|
+
def setup_dependencies(
|
|
534
|
+
component: "WebUIBackendComponent",
|
|
535
|
+
database_url: str = None,
|
|
536
|
+
platform_database_url: str = None
|
|
537
|
+
):
|
|
502
538
|
"""
|
|
503
|
-
|
|
504
|
-
backward compatibility with existing API contracts.
|
|
539
|
+
Initialize dependencies for both runtime and platform databases.
|
|
505
540
|
|
|
506
|
-
|
|
541
|
+
Args:
|
|
542
|
+
component: WebUIBackendComponent instance
|
|
543
|
+
database_url: Runtime database URL (sessions, tasks, chat).
|
|
544
|
+
If None, runs in compatibility mode with in-memory sessions.
|
|
545
|
+
platform_database_url: Platform database URL (agents, connectors, deployments).
|
|
546
|
+
If None, platform features will be unavailable (returns 501).
|
|
507
547
|
|
|
508
548
|
This function is idempotent and safe to call multiple times.
|
|
509
549
|
"""
|
|
@@ -516,7 +556,7 @@ def setup_dependencies(component: "WebUIBackendComponent", database_url: str = N
|
|
|
516
556
|
dependencies.set_component_instance(component)
|
|
517
557
|
|
|
518
558
|
if database_url:
|
|
519
|
-
_setup_database(component, database_url)
|
|
559
|
+
_setup_database(component, database_url, platform_database_url)
|
|
520
560
|
else:
|
|
521
561
|
log.warning(
|
|
522
562
|
"No database URL provided - using in-memory session storage (data not persisted across restarts)"
|
|
@@ -564,7 +604,7 @@ def _setup_routers() -> None:
|
|
|
564
604
|
app.include_router(user_router, prefix=f"{api_prefix}/users", tags=["Users"])
|
|
565
605
|
app.include_router(config.router, prefix=api_prefix, tags=["Config"])
|
|
566
606
|
app.include_router(agent_cards.router, prefix=api_prefix, tags=["Agent Cards"])
|
|
567
|
-
app.include_router(
|
|
607
|
+
app.include_router(task_router, prefix=api_prefix, tags=["Tasks"])
|
|
568
608
|
app.include_router(sse.router, prefix=f"{api_prefix}/sse", tags=["SSE"])
|
|
569
609
|
app.include_router(
|
|
570
610
|
artifacts.router, prefix=f"{api_prefix}/artifacts", tags=["Artifacts"]
|
|
@@ -576,6 +616,7 @@ def _setup_routers() -> None:
|
|
|
576
616
|
)
|
|
577
617
|
app.include_router(people.router, prefix=api_prefix, tags=["People"])
|
|
578
618
|
app.include_router(auth.router, prefix=api_prefix, tags=["Auth"])
|
|
619
|
+
app.include_router(projects.router, prefix=api_prefix, tags=["Projects"])
|
|
579
620
|
app.include_router(feedback.router, prefix=api_prefix, tags=["Feedback"])
|
|
580
621
|
log.info("Legacy routers mounted for endpoints not yet migrated")
|
|
581
622
|
|
|
@@ -3,10 +3,20 @@ Repository layer containing all data access logic organized by entity type.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
# Interfaces
|
|
6
|
-
from .interfaces import
|
|
6
|
+
from .interfaces import (
|
|
7
|
+
IChatTaskRepository,
|
|
8
|
+
IFeedbackRepository,
|
|
9
|
+
IProjectRepository,
|
|
10
|
+
ISessionRepository,
|
|
11
|
+
ITaskRepository,
|
|
12
|
+
)
|
|
7
13
|
|
|
8
14
|
# Implementations
|
|
15
|
+
from .chat_task_repository import ChatTaskRepository
|
|
16
|
+
from .feedback_repository import FeedbackRepository
|
|
17
|
+
from .project_repository import ProjectRepository
|
|
9
18
|
from .session_repository import SessionRepository
|
|
19
|
+
from .task_repository import TaskRepository
|
|
10
20
|
|
|
11
21
|
# Entities (re-exported for convenience)
|
|
12
22
|
from .entities.session import Session
|
|
@@ -17,9 +27,17 @@ from .models.session_model import SessionModel
|
|
|
17
27
|
|
|
18
28
|
__all__ = [
|
|
19
29
|
# Interfaces
|
|
30
|
+
"IChatTaskRepository",
|
|
31
|
+
"IFeedbackRepository",
|
|
32
|
+
"IProjectRepository",
|
|
20
33
|
"ISessionRepository",
|
|
34
|
+
"ITaskRepository",
|
|
21
35
|
# Implementations
|
|
36
|
+
"ChatTaskRepository",
|
|
37
|
+
"FeedbackRepository",
|
|
38
|
+
"ProjectRepository",
|
|
22
39
|
"SessionRepository",
|
|
40
|
+
"TaskRepository",
|
|
23
41
|
# Entities
|
|
24
42
|
"Session",
|
|
25
43
|
# Models
|
|
@@ -1,29 +1,74 @@
|
|
|
1
1
|
# DEVELOPER GUIDE: entities
|
|
2
2
|
|
|
3
3
|
## Quick Summary
|
|
4
|
-
The entities directory contains domain entities for the repository layer, providing core business objects for managing chat sessions,
|
|
4
|
+
The entities directory contains domain entities for the repository layer, providing core business objects for managing chat sessions, tasks, feedback, and events with built-in validation and business logic.
|
|
5
5
|
|
|
6
6
|
## Files Overview
|
|
7
|
-
- `__init__.py` - Exports the main domain entities (
|
|
7
|
+
- `__init__.py` - Exports the main domain entities (ChatTask, Feedback, Session, Task, TaskEvent)
|
|
8
|
+
- `chat_task.py` - ChatTask entity for managing chat conversations with JSON validation
|
|
8
9
|
- `feedback.py` - Feedback entity for user ratings and comments on tasks
|
|
9
|
-
- `message.py` - Message entity with content validation and sender type checking
|
|
10
10
|
- `session.py` - Session entity with name management and access control
|
|
11
|
-
- `
|
|
12
|
-
- `
|
|
13
|
-
- `task_event.py` - Task event entity for tracking events related to tasks
|
|
11
|
+
- `task.py` - Task entity for tracking user tasks with token usage metrics
|
|
12
|
+
- `task_event.py` - TaskEvent entity for tracking events related to tasks
|
|
14
13
|
|
|
15
14
|
## Developer API Reference
|
|
16
15
|
|
|
17
16
|
### __init__.py
|
|
18
17
|
**Purpose:** Provides centralized imports for all domain entities
|
|
19
|
-
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import
|
|
18
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import ChatTask, Feedback, Session, Task, TaskEvent`
|
|
19
|
+
|
|
20
|
+
### chat_task.py
|
|
21
|
+
**Purpose:** Defines the ChatTask domain entity for managing chat conversations with JSON validation
|
|
22
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import ChatTask`
|
|
23
|
+
|
|
24
|
+
**Classes:**
|
|
25
|
+
- `ChatTask(id: str, session_id: str, user_id: str, message_bubbles: str, created_time: int, user_message: str | None = None, task_metadata: str | None = None, updated_time: int | None = None)` - ChatTask domain entity with business logic
|
|
26
|
+
- `add_feedback(feedback_type: str, feedback_text: str | None = None) -> None` - Add or update feedback for this task
|
|
27
|
+
- `get_feedback() -> dict[str, Any] | None` - Get feedback for this task
|
|
28
|
+
- `id: str` - Unique task identifier
|
|
29
|
+
- `session_id: str` - Associated session identifier
|
|
30
|
+
- `user_id: str` - User who owns the task
|
|
31
|
+
- `user_message: str | None` - Optional user message
|
|
32
|
+
- `message_bubbles: str` - JSON string containing message bubbles (must be non-empty JSON array)
|
|
33
|
+
- `task_metadata: str | None` - Optional JSON string for task metadata
|
|
34
|
+
- `created_time: int` - Task creation timestamp
|
|
35
|
+
- `updated_time: int | None` - Last update timestamp
|
|
36
|
+
|
|
37
|
+
**Usage Examples:**
|
|
38
|
+
```python
|
|
39
|
+
from solace_agent_mesh.gateway.http_sse.repository.entities import ChatTask
|
|
40
|
+
import json
|
|
41
|
+
|
|
42
|
+
# Create a chat task
|
|
43
|
+
message_bubbles = json.dumps([
|
|
44
|
+
{"type": "user", "content": "Hello"},
|
|
45
|
+
{"type": "agent", "content": "Hi there!"}
|
|
46
|
+
])
|
|
47
|
+
|
|
48
|
+
chat_task = ChatTask(
|
|
49
|
+
id="chat_123",
|
|
50
|
+
session_id="session_456",
|
|
51
|
+
user_id="user_789",
|
|
52
|
+
user_message="Hello",
|
|
53
|
+
message_bubbles=message_bubbles,
|
|
54
|
+
created_time=1640995200000
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
# Add feedback
|
|
58
|
+
chat_task.add_feedback("positive", "Great response!")
|
|
59
|
+
|
|
60
|
+
# Get feedback
|
|
61
|
+
feedback = chat_task.get_feedback()
|
|
62
|
+
if feedback:
|
|
63
|
+
print(f"Feedback type: {feedback['type']}")
|
|
64
|
+
```
|
|
20
65
|
|
|
21
66
|
### feedback.py
|
|
22
67
|
**Purpose:** Defines the Feedback domain entity for user ratings and comments
|
|
23
68
|
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Feedback`
|
|
24
69
|
|
|
25
70
|
**Classes:**
|
|
26
|
-
- `Feedback(id: str, session_id: str, task_id: str, user_id: str, rating: str, comment: str | None = None
|
|
71
|
+
- `Feedback(id: str, session_id: str, task_id: str, user_id: str, rating: str, created_time: int, comment: str | None = None)` - Feedback domain entity
|
|
27
72
|
- `id: str` - Unique feedback identifier
|
|
28
73
|
- `session_id: str` - Associated session identifier
|
|
29
74
|
- `task_id: str` - Associated task identifier
|
|
@@ -48,54 +93,12 @@ feedback = Feedback(
|
|
|
48
93
|
)
|
|
49
94
|
```
|
|
50
95
|
|
|
51
|
-
### message.py
|
|
52
|
-
**Purpose:** Defines the Message domain entity with business logic for chat messages
|
|
53
|
-
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Message`
|
|
54
|
-
|
|
55
|
-
**Classes:**
|
|
56
|
-
- `Message(id: MessageId, session_id: SessionId, message: str, sender_type: SenderType, sender_name: str, message_type: MessageType = MessageType.TEXT, created_time: int)` - Message domain entity with business logic
|
|
57
|
-
- `validate_message_content() -> None` - Validates message content is not empty and under 10MB limit
|
|
58
|
-
- `is_from_user() -> bool` - Checks if message is from a user
|
|
59
|
-
- `is_from_agent() -> bool` - Checks if message is from an agent
|
|
60
|
-
- `is_system_message() -> bool` - Checks if message is a system message
|
|
61
|
-
- `id: MessageId` - Unique message identifier
|
|
62
|
-
- `session_id: SessionId` - Associated session identifier
|
|
63
|
-
- `message: str` - Message content
|
|
64
|
-
- `sender_type: SenderType` - Type of sender (USER, AGENT, SYSTEM)
|
|
65
|
-
- `sender_name: str` - Name of the message sender
|
|
66
|
-
- `message_type: MessageType` - Type of message content
|
|
67
|
-
- `created_time: int` - Message creation timestamp
|
|
68
|
-
|
|
69
|
-
**Usage Examples:**
|
|
70
|
-
```python
|
|
71
|
-
from solace_agent_mesh.gateway.http_sse.repository.entities import Message
|
|
72
|
-
from solace_agent_mesh.gateway.http_sse.shared.enums import SenderType, MessageType
|
|
73
|
-
|
|
74
|
-
# Create a user message
|
|
75
|
-
message = Message(
|
|
76
|
-
id="msg_123",
|
|
77
|
-
session_id="session_456",
|
|
78
|
-
message="Hello, how can I help?",
|
|
79
|
-
sender_type=SenderType.USER,
|
|
80
|
-
sender_name="John Doe",
|
|
81
|
-
message_type=MessageType.TEXT,
|
|
82
|
-
created_time=1640995200000
|
|
83
|
-
)
|
|
84
|
-
|
|
85
|
-
# Validate message content
|
|
86
|
-
message.validate_message_content()
|
|
87
|
-
|
|
88
|
-
# Check sender type
|
|
89
|
-
if message.is_from_user():
|
|
90
|
-
print("Message from user")
|
|
91
|
-
```
|
|
92
|
-
|
|
93
96
|
### session.py
|
|
94
97
|
**Purpose:** Defines the Session domain entity with business logic for chat sessions
|
|
95
98
|
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Session`
|
|
96
99
|
|
|
97
100
|
**Classes:**
|
|
98
|
-
- `Session(id: SessionId, user_id: UserId, name: str | None = None, agent_id: AgentId | None = None,
|
|
101
|
+
- `Session(id: SessionId, user_id: UserId, created_time: int, name: str | None = None, agent_id: AgentId | None = None, updated_time: int | None = None)` - Session domain entity with business logic
|
|
99
102
|
- `update_name(new_name: str) -> None` - Updates session name with validation and sets updated_time
|
|
100
103
|
- `mark_activity() -> None` - Marks session as having recent activity by updating timestamp
|
|
101
104
|
- `can_be_deleted_by_user(user_id: UserId) -> bool` - Checks if user can delete this session
|
|
@@ -131,51 +134,6 @@ if session.can_be_accessed_by_user("user_456"):
|
|
|
131
134
|
print("User can access this session")
|
|
132
135
|
```
|
|
133
136
|
|
|
134
|
-
### session_history.py
|
|
135
|
-
**Purpose:** Defines a composite entity that combines a session with its message history
|
|
136
|
-
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import SessionHistory`
|
|
137
|
-
|
|
138
|
-
**Classes:**
|
|
139
|
-
- `SessionHistory(session: Session, messages: list[Message] = [], total_message_count: int = 0)` - Composite entity representing a session with its messages
|
|
140
|
-
- `session: Session` - The session entity
|
|
141
|
-
- `messages: list[Message]` - List of messages in the session
|
|
142
|
-
- `total_message_count: int` - Total count of messages (may exceed messages list length for pagination)
|
|
143
|
-
|
|
144
|
-
**Usage Examples:**
|
|
145
|
-
```python
|
|
146
|
-
from solace_agent_mesh.gateway.http_sse.repository.entities import SessionHistory, Session, Message
|
|
147
|
-
from solace_agent_mesh.gateway.http_sse.shared.enums import SenderType
|
|
148
|
-
|
|
149
|
-
# Create session history
|
|
150
|
-
session = Session(
|
|
151
|
-
id="session_123",
|
|
152
|
-
user_id="user_456",
|
|
153
|
-
created_time=1640995200000
|
|
154
|
-
)
|
|
155
|
-
|
|
156
|
-
messages = [
|
|
157
|
-
Message(
|
|
158
|
-
id="msg_1",
|
|
159
|
-
session_id="session_123",
|
|
160
|
-
message="Hello",
|
|
161
|
-
sender_type=SenderType.USER,
|
|
162
|
-
sender_name="John",
|
|
163
|
-
created_time=1640995200000
|
|
164
|
-
)
|
|
165
|
-
]
|
|
166
|
-
|
|
167
|
-
history = SessionHistory(
|
|
168
|
-
session=session,
|
|
169
|
-
messages=messages,
|
|
170
|
-
total_message_count=1
|
|
171
|
-
)
|
|
172
|
-
|
|
173
|
-
# Access session and messages
|
|
174
|
-
print(f"Session: {history.session.id}")
|
|
175
|
-
print(f"Message count: {len(history.messages)}")
|
|
176
|
-
print(f"Total messages: {history.total_message_count}")
|
|
177
|
-
```
|
|
178
|
-
|
|
179
137
|
### task.py
|
|
180
138
|
**Purpose:** Defines the Task domain entity for tracking user tasks with token usage metrics
|
|
181
139
|
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Task`
|
|
@@ -225,7 +183,7 @@ task_with_tokens = Task(
|
|
|
225
183
|
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import TaskEvent`
|
|
226
184
|
|
|
227
185
|
**Classes:**
|
|
228
|
-
- `TaskEvent(id: str, task_id: str,
|
|
186
|
+
- `TaskEvent(id: str, task_id: str, created_time: int, topic: str, direction: str, payload: dict[str, Any], user_id: str | None = None)` - TaskEvent domain entity
|
|
229
187
|
- `id: str` - Unique event identifier
|
|
230
188
|
- `task_id: str` - Associated task identifier
|
|
231
189
|
- `user_id: str | None` - Optional user identifier
|
|
@@ -260,4 +218,4 @@ system_event = TaskEvent(
|
|
|
260
218
|
)
|
|
261
219
|
```
|
|
262
220
|
|
|
263
|
-
# content_hash:
|
|
221
|
+
# content_hash: d7b07fd8577e43715a286030d4119267ddff5483180284a16dc6d8aab19fd089
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project domain entity.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from ...shared import now_epoch_ms
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class Project(BaseModel):
|
|
12
|
+
"""Project domain entity with business logic."""
|
|
13
|
+
|
|
14
|
+
id: str
|
|
15
|
+
name: str = Field(..., min_length=1, max_length=255)
|
|
16
|
+
user_id: str
|
|
17
|
+
description: Optional[str] = Field(None, max_length=1000)
|
|
18
|
+
system_prompt: Optional[str] = Field(None, max_length=4000)
|
|
19
|
+
default_agent_id: Optional[str] = None
|
|
20
|
+
created_at: int
|
|
21
|
+
updated_at: Optional[int] = None
|
|
22
|
+
deleted_at: Optional[int] = None
|
|
23
|
+
deleted_by: Optional[str] = None
|
|
24
|
+
|
|
25
|
+
def update_name(self, new_name: str) -> None:
|
|
26
|
+
"""Update project name with validation."""
|
|
27
|
+
if not new_name or len(new_name.strip()) == 0:
|
|
28
|
+
raise ValueError("Project name cannot be empty")
|
|
29
|
+
if len(new_name) > 255:
|
|
30
|
+
raise ValueError("Project name cannot exceed 255 characters")
|
|
31
|
+
|
|
32
|
+
self.name = new_name.strip()
|
|
33
|
+
self.updated_at = now_epoch_ms()
|
|
34
|
+
|
|
35
|
+
def update_description(self, new_description: Optional[str]) -> None:
|
|
36
|
+
"""Update project description with validation."""
|
|
37
|
+
if new_description is not None:
|
|
38
|
+
if len(new_description) > 1000:
|
|
39
|
+
raise ValueError("Project description cannot exceed 1000 characters")
|
|
40
|
+
self.description = new_description.strip() if new_description else None
|
|
41
|
+
else:
|
|
42
|
+
self.description = None
|
|
43
|
+
|
|
44
|
+
self.updated_at = now_epoch_ms()
|
|
45
|
+
|
|
46
|
+
def update_default_agent(self, agent_id: Optional[str]) -> None:
|
|
47
|
+
"""Update project default agent."""
|
|
48
|
+
self.default_agent_id = agent_id
|
|
49
|
+
self.updated_at = now_epoch_ms()
|
|
50
|
+
|
|
51
|
+
def soft_delete(self, user_id: str) -> None:
|
|
52
|
+
"""Soft delete the project."""
|
|
53
|
+
if not self.can_be_deleted_by_user(user_id):
|
|
54
|
+
raise ValueError("User does not have permission to delete this project")
|
|
55
|
+
|
|
56
|
+
self.deleted_at = now_epoch_ms()
|
|
57
|
+
self.deleted_by = user_id
|
|
58
|
+
self.updated_at = now_epoch_ms()
|
|
59
|
+
|
|
60
|
+
def is_deleted(self) -> bool:
|
|
61
|
+
"""Check if project is soft deleted."""
|
|
62
|
+
return self.deleted_at is not None
|
|
63
|
+
|
|
64
|
+
def can_be_accessed_by_user(self, user_id: str) -> bool:
|
|
65
|
+
"""Check if project can be accessed by the given user."""
|
|
66
|
+
# User projects are only accessible by their owner and not deleted
|
|
67
|
+
return self.user_id == user_id and not self.is_deleted()
|
|
68
|
+
|
|
69
|
+
def can_be_edited_by_user(self, user_id: str) -> bool:
|
|
70
|
+
"""Check if project can be edited by the given user."""
|
|
71
|
+
# Users can only edit their own projects that are not deleted
|
|
72
|
+
return self.user_id == user_id and not self.is_deleted()
|
|
73
|
+
|
|
74
|
+
def can_be_deleted_by_user(self, user_id: str) -> bool:
|
|
75
|
+
"""Check if project can be deleted by the given user."""
|
|
76
|
+
# Users can only delete their own projects that are not already deleted
|
|
77
|
+
return self.user_id == user_id and not self.is_deleted()
|
|
78
|
+
|
|
79
|
+
def mark_as_updated(self) -> None:
|
|
80
|
+
"""Mark project as updated."""
|
|
81
|
+
self.updated_at = now_epoch_ms()
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Project user access domain entity.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from typing import Optional
|
|
6
|
+
from pydantic import BaseModel, Field
|
|
7
|
+
|
|
8
|
+
from ...shared import now_epoch_ms
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ProjectUser(BaseModel):
|
|
12
|
+
"""
|
|
13
|
+
Project user access domain entity.
|
|
14
|
+
|
|
15
|
+
Represents a user's access to a project with a specific role.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
id: str
|
|
19
|
+
project_id: str
|
|
20
|
+
user_id: str
|
|
21
|
+
role: str = Field(..., pattern="^(owner|editor|viewer)$")
|
|
22
|
+
added_at: int
|
|
23
|
+
added_by_user_id: str
|
|
24
|
+
|
|
25
|
+
def can_edit_project(self) -> bool:
|
|
26
|
+
"""Check if this user can edit the project based on their role."""
|
|
27
|
+
return self.role in ["owner", "editor"]
|
|
28
|
+
|
|
29
|
+
def can_manage_users(self) -> bool:
|
|
30
|
+
"""Check if this user can manage other users' access to the project."""
|
|
31
|
+
return self.role == "owner"
|
|
32
|
+
|
|
33
|
+
def can_view_project(self) -> bool:
|
|
34
|
+
"""Check if this user can view the project."""
|
|
35
|
+
return self.role in ["owner", "editor", "viewer"]
|
|
36
|
+
|
|
37
|
+
def update_role(self, new_role: str) -> None:
|
|
38
|
+
"""Update the user's role with validation."""
|
|
39
|
+
valid_roles = ["owner", "editor", "viewer"]
|
|
40
|
+
if new_role not in valid_roles:
|
|
41
|
+
raise ValueError(f"Invalid role. Must be one of: {', '.join(valid_roles)}")
|
|
42
|
+
|
|
43
|
+
self.role = new_role
|
|
44
|
+
|
|
45
|
+
class Config:
|
|
46
|
+
"""Pydantic configuration."""
|
|
47
|
+
frozen = False
|
|
@@ -17,8 +17,12 @@ class Session(BaseModel):
|
|
|
17
17
|
user_id: UserId
|
|
18
18
|
name: str | None = None
|
|
19
19
|
agent_id: AgentId | None = None
|
|
20
|
+
project_id: str | None = None
|
|
21
|
+
project_name: str | None = None
|
|
20
22
|
created_time: int
|
|
21
23
|
updated_time: int | None = None
|
|
24
|
+
deleted_at: int | None = None
|
|
25
|
+
deleted_by: str | None = None
|
|
22
26
|
|
|
23
27
|
def update_name(self, new_name: str) -> None:
|
|
24
28
|
"""Update session name with validation."""
|
|
@@ -34,10 +38,28 @@ class Session(BaseModel):
|
|
|
34
38
|
"""Mark session as having recent activity."""
|
|
35
39
|
self.updated_time = now_epoch_ms()
|
|
36
40
|
|
|
41
|
+
def soft_delete(self, user_id: UserId) -> None:
|
|
42
|
+
"""Soft delete the session."""
|
|
43
|
+
if not self.can_be_deleted_by_user(user_id):
|
|
44
|
+
raise ValueError("User does not have permission to delete this session")
|
|
45
|
+
|
|
46
|
+
self.deleted_at = now_epoch_ms()
|
|
47
|
+
self.deleted_by = user_id
|
|
48
|
+
self.updated_time = now_epoch_ms()
|
|
49
|
+
|
|
50
|
+
def is_deleted(self) -> bool:
|
|
51
|
+
"""Check if session is soft deleted."""
|
|
52
|
+
return self.deleted_at is not None
|
|
53
|
+
|
|
54
|
+
def move_to_project(self, new_project_id: str | None) -> None:
|
|
55
|
+
"""Move session to a different project."""
|
|
56
|
+
self.project_id = new_project_id
|
|
57
|
+
self.updated_time = now_epoch_ms()
|
|
58
|
+
|
|
37
59
|
def can_be_deleted_by_user(self, user_id: UserId) -> bool:
|
|
38
60
|
"""Check if user can delete this session."""
|
|
39
61
|
return self.user_id == user_id
|
|
40
62
|
|
|
41
63
|
def can_be_accessed_by_user(self, user_id: UserId) -> bool:
|
|
42
64
|
"""Check if user can access this session."""
|
|
43
|
-
return self.user_id == user_id
|
|
65
|
+
return self.user_id == user_id and not self.is_deleted()
|
|
@@ -4,6 +4,8 @@ Feedback repository implementation using SQLAlchemy.
|
|
|
4
4
|
|
|
5
5
|
from sqlalchemy.orm import Session as DBSession
|
|
6
6
|
|
|
7
|
+
from ..shared.pagination import PaginationParams
|
|
8
|
+
from ..shared.types import UserId
|
|
7
9
|
from .entities import Feedback
|
|
8
10
|
from .interfaces import IFeedbackRepository
|
|
9
11
|
from .models import FeedbackModel
|
|
@@ -28,6 +30,51 @@ class FeedbackRepository(IFeedbackRepository):
|
|
|
28
30
|
session.refresh(model)
|
|
29
31
|
return self._model_to_entity(model)
|
|
30
32
|
|
|
33
|
+
def search(
|
|
34
|
+
self,
|
|
35
|
+
session: DBSession,
|
|
36
|
+
user_id: UserId,
|
|
37
|
+
start_date: int | None = None,
|
|
38
|
+
end_date: int | None = None,
|
|
39
|
+
task_id: str | None = None,
|
|
40
|
+
session_id: str | None = None,
|
|
41
|
+
rating: str | None = None,
|
|
42
|
+
pagination: PaginationParams | None = None,
|
|
43
|
+
) -> list[Feedback]:
|
|
44
|
+
"""
|
|
45
|
+
Search feedback with flexible filtering.
|
|
46
|
+
All filters are optional and can be combined.
|
|
47
|
+
"""
|
|
48
|
+
query = session.query(FeedbackModel)
|
|
49
|
+
|
|
50
|
+
# User filter (unless admin querying all users)
|
|
51
|
+
if user_id != "*":
|
|
52
|
+
query = query.filter(FeedbackModel.user_id == user_id)
|
|
53
|
+
|
|
54
|
+
# Time-based filters
|
|
55
|
+
if start_date:
|
|
56
|
+
query = query.filter(FeedbackModel.created_time >= start_date)
|
|
57
|
+
if end_date:
|
|
58
|
+
query = query.filter(FeedbackModel.created_time <= end_date)
|
|
59
|
+
|
|
60
|
+
# Resource-based filters
|
|
61
|
+
if task_id:
|
|
62
|
+
query = query.filter(FeedbackModel.task_id == task_id)
|
|
63
|
+
if session_id:
|
|
64
|
+
query = query.filter(FeedbackModel.session_id == session_id)
|
|
65
|
+
if rating:
|
|
66
|
+
query = query.filter(FeedbackModel.rating == rating)
|
|
67
|
+
|
|
68
|
+
# Order by most recent first
|
|
69
|
+
query = query.order_by(FeedbackModel.created_time.desc())
|
|
70
|
+
|
|
71
|
+
# Apply pagination
|
|
72
|
+
if pagination:
|
|
73
|
+
query = query.offset(pagination.offset).limit(pagination.page_size)
|
|
74
|
+
|
|
75
|
+
models = query.all()
|
|
76
|
+
return [self._model_to_entity(model) for model in models]
|
|
77
|
+
|
|
31
78
|
def delete_feedback_older_than(self, session: DBSession, cutoff_time_ms: int, batch_size: int) -> int:
|
|
32
79
|
"""
|
|
33
80
|
Delete feedback records older than the cutoff time.
|