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
|
@@ -9,6 +9,8 @@ from sqlalchemy.orm import Session as DBSession
|
|
|
9
9
|
from ..shared.pagination import PaginationParams
|
|
10
10
|
from ..shared.types import SessionId, UserId
|
|
11
11
|
from .entities import Feedback, Session, Task, TaskEvent
|
|
12
|
+
from .entities.project import Project
|
|
13
|
+
from ..routers.dto.requests.project_requests import ProjectFilter
|
|
12
14
|
|
|
13
15
|
if TYPE_CHECKING:
|
|
14
16
|
from .entities import ChatTask
|
|
@@ -19,14 +21,14 @@ class ISessionRepository(ABC):
|
|
|
19
21
|
|
|
20
22
|
@abstractmethod
|
|
21
23
|
def find_by_user(
|
|
22
|
-
self, session: DBSession, user_id: UserId, pagination: PaginationParams | None = None
|
|
24
|
+
self, session: DBSession, user_id: UserId, pagination: PaginationParams | None = None, project_id: str | None = None
|
|
23
25
|
) -> list[Session]:
|
|
24
|
-
"""Find all sessions for a specific user."""
|
|
26
|
+
"""Find all sessions for a specific user, optionally filtered by project."""
|
|
25
27
|
pass
|
|
26
28
|
|
|
27
29
|
@abstractmethod
|
|
28
|
-
def count_by_user(self, session: DBSession, user_id: UserId) -> int:
|
|
29
|
-
"""Count total sessions for a specific user."""
|
|
30
|
+
def count_by_user(self, session: DBSession, user_id: UserId, project_id: str | None = None) -> int:
|
|
31
|
+
"""Count total sessions for a specific user, optionally filtered by project."""
|
|
30
32
|
pass
|
|
31
33
|
|
|
32
34
|
@abstractmethod
|
|
@@ -46,6 +48,41 @@ class ISessionRepository(ABC):
|
|
|
46
48
|
"""Delete a session belonging to a user."""
|
|
47
49
|
pass
|
|
48
50
|
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def soft_delete(self, session: DBSession, session_id: SessionId, user_id: UserId) -> bool:
|
|
53
|
+
"""Soft delete a session belonging to a user."""
|
|
54
|
+
pass
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def move_to_project(
|
|
58
|
+
self, session: DBSession, session_id: SessionId, user_id: UserId, new_project_id: str | None
|
|
59
|
+
) -> Session | None:
|
|
60
|
+
"""Move a session to a different project."""
|
|
61
|
+
pass
|
|
62
|
+
|
|
63
|
+
@abstractmethod
|
|
64
|
+
def search(
|
|
65
|
+
self,
|
|
66
|
+
session: DBSession,
|
|
67
|
+
user_id: UserId,
|
|
68
|
+
query: str,
|
|
69
|
+
pagination: PaginationParams | None = None,
|
|
70
|
+
project_id: str | None = None
|
|
71
|
+
) -> list[Session]:
|
|
72
|
+
"""Search sessions by name or content."""
|
|
73
|
+
pass
|
|
74
|
+
|
|
75
|
+
@abstractmethod
|
|
76
|
+
def count_search_results(
|
|
77
|
+
self,
|
|
78
|
+
session: DBSession,
|
|
79
|
+
user_id: UserId,
|
|
80
|
+
query: str,
|
|
81
|
+
project_id: str | None = None
|
|
82
|
+
) -> int:
|
|
83
|
+
"""Count search results for pagination."""
|
|
84
|
+
pass
|
|
85
|
+
|
|
49
86
|
|
|
50
87
|
class ITaskRepository(ABC):
|
|
51
88
|
"""Interface for task data access operations."""
|
|
@@ -99,6 +136,37 @@ class IFeedbackRepository(ABC):
|
|
|
99
136
|
"""Save feedback."""
|
|
100
137
|
pass
|
|
101
138
|
|
|
139
|
+
@abstractmethod
|
|
140
|
+
def search(
|
|
141
|
+
self,
|
|
142
|
+
session: DBSession,
|
|
143
|
+
user_id: UserId,
|
|
144
|
+
start_date: int | None = None,
|
|
145
|
+
end_date: int | None = None,
|
|
146
|
+
task_id: str | None = None,
|
|
147
|
+
session_id: str | None = None,
|
|
148
|
+
rating: str | None = None,
|
|
149
|
+
pagination: PaginationParams | None = None,
|
|
150
|
+
) -> list[Feedback]:
|
|
151
|
+
"""
|
|
152
|
+
Search feedback with flexible filtering.
|
|
153
|
+
All filters are optional and can be combined.
|
|
154
|
+
|
|
155
|
+
Args:
|
|
156
|
+
session: Database session
|
|
157
|
+
user_id: User ID to filter by, or "*" for all users (admin)
|
|
158
|
+
start_date: Start of date range in epoch milliseconds
|
|
159
|
+
end_date: End of date range in epoch milliseconds
|
|
160
|
+
task_id: Filter by specific task ID
|
|
161
|
+
session_id: Filter by specific session ID
|
|
162
|
+
rating: Filter by rating type ("up" or "down")
|
|
163
|
+
pagination: Pagination parameters
|
|
164
|
+
|
|
165
|
+
Returns:
|
|
166
|
+
List of feedback entries matching the filters
|
|
167
|
+
"""
|
|
168
|
+
pass
|
|
169
|
+
|
|
102
170
|
@abstractmethod
|
|
103
171
|
def delete_feedback_older_than(self, session: DBSession, cutoff_time_ms: int, batch_size: int) -> int:
|
|
104
172
|
"""Delete feedback older than cutoff time using batch deletion."""
|
|
@@ -129,3 +197,43 @@ class IChatTaskRepository(ABC):
|
|
|
129
197
|
def delete_by_session(self, session: DBSession, session_id: SessionId) -> bool:
|
|
130
198
|
"""Delete all tasks for a session."""
|
|
131
199
|
pass
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class IProjectRepository(ABC):
|
|
203
|
+
"""Interface for project repository operations."""
|
|
204
|
+
|
|
205
|
+
@abstractmethod
|
|
206
|
+
def create_project(self, name: str, user_id: str, description: Optional[str] = None,
|
|
207
|
+
system_prompt: Optional[str] = None) -> Project:
|
|
208
|
+
"""Create a new user project."""
|
|
209
|
+
pass
|
|
210
|
+
|
|
211
|
+
@abstractmethod
|
|
212
|
+
def get_user_projects(self, user_id: str) -> list[Project]:
|
|
213
|
+
"""Get all projects owned by a specific user."""
|
|
214
|
+
pass
|
|
215
|
+
|
|
216
|
+
@abstractmethod
|
|
217
|
+
def get_filtered_projects(self, project_filter: ProjectFilter) -> list[Project]:
|
|
218
|
+
"""Get projects based on filter criteria."""
|
|
219
|
+
pass
|
|
220
|
+
|
|
221
|
+
@abstractmethod
|
|
222
|
+
def get_by_id(self, project_id: str, user_id: str) -> Optional[Project]:
|
|
223
|
+
"""Get a project by its ID, ensuring user access."""
|
|
224
|
+
pass
|
|
225
|
+
|
|
226
|
+
@abstractmethod
|
|
227
|
+
def update(self, project_id: str, user_id: str, update_data: dict) -> Optional[Project]:
|
|
228
|
+
"""Update a project with the given data, ensuring user access."""
|
|
229
|
+
pass
|
|
230
|
+
|
|
231
|
+
@abstractmethod
|
|
232
|
+
def delete(self, project_id: str, user_id: str) -> bool:
|
|
233
|
+
"""Delete a project by its ID, ensuring user access."""
|
|
234
|
+
pass
|
|
235
|
+
|
|
236
|
+
@abstractmethod
|
|
237
|
+
def soft_delete(self, project_id: str, user_id: str) -> bool:
|
|
238
|
+
"""Soft delete a project by its ID, ensuring user access."""
|
|
239
|
+
pass
|
|
@@ -5,6 +5,8 @@ SQLAlchemy models and Pydantic models for database persistence.
|
|
|
5
5
|
from .base import Base
|
|
6
6
|
from .chat_task_model import ChatTaskModel
|
|
7
7
|
from .feedback_model import FeedbackModel
|
|
8
|
+
from .project_model import ProjectModel, CreateProjectModel, UpdateProjectModel
|
|
9
|
+
from .project_user_model import ProjectUserModel, CreateProjectUserModel, UpdateProjectUserModel
|
|
8
10
|
from .session_model import SessionModel, CreateSessionModel, UpdateSessionModel
|
|
9
11
|
from .task_event_model import TaskEventModel
|
|
10
12
|
from .task_model import TaskModel
|
|
@@ -12,10 +14,16 @@ from .task_model import TaskModel
|
|
|
12
14
|
__all__ = [
|
|
13
15
|
"Base",
|
|
14
16
|
"ChatTaskModel",
|
|
17
|
+
"FeedbackModel",
|
|
18
|
+
"ProjectModel",
|
|
19
|
+
"ProjectUserModel",
|
|
15
20
|
"SessionModel",
|
|
21
|
+
"CreateProjectModel",
|
|
22
|
+
"UpdateProjectModel",
|
|
23
|
+
"CreateProjectUserModel",
|
|
24
|
+
"UpdateProjectUserModel",
|
|
16
25
|
"CreateSessionModel",
|
|
17
26
|
"UpdateSessionModel",
|
|
18
27
|
"TaskEventModel",
|
|
19
28
|
"TaskModel",
|
|
20
|
-
"FeedbackModel",
|
|
21
29
|
]
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
## Quick Summary
|
|
2
|
-
This directory contains SQLAlchemy ORM models and Pydantic schemas for database persistence in the HTTP SSE gateway. It provides models for managing chat sessions,
|
|
2
|
+
This directory contains SQLAlchemy ORM models and Pydantic schemas for database persistence in the HTTP SSE gateway. It provides models for managing chat sessions, tasks, task events, and user feedback with proper relationships and database schema definitions.
|
|
3
3
|
|
|
4
4
|
## Files Overview
|
|
5
5
|
- `__init__.py` - Package initialization exposing all SQLAlchemy and Pydantic models
|
|
6
6
|
- `base.py` - SQLAlchemy declarative base configuration
|
|
7
|
+
- `chat_task_model.py` - ChatTaskModel for storing chat tasks with session relationships
|
|
7
8
|
- `feedback_model.py` - FeedbackModel for storing user feedback on tasks
|
|
8
|
-
- `message_model.py` - MessageModel and Pydantic schemas for chat messages with session relationships
|
|
9
9
|
- `session_model.py` - SessionModel and Pydantic schemas for managing chat sessions
|
|
10
10
|
- `task_event_model.py` - TaskEventModel for storing A2A task events with task relationships
|
|
11
11
|
- `task_model.py` - TaskModel for managing tasks with event relationships and token usage tracking
|
|
@@ -14,7 +14,7 @@ This directory contains SQLAlchemy ORM models and Pydantic schemas for database
|
|
|
14
14
|
|
|
15
15
|
### __init__.py
|
|
16
16
|
**Purpose:** Package entry point that exposes all SQLAlchemy models and Pydantic schemas
|
|
17
|
-
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.models import Base,
|
|
17
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.models import Base, ChatTaskModel, FeedbackModel, SessionModel, CreateSessionModel, UpdateSessionModel, TaskEventModel, TaskModel`
|
|
18
18
|
|
|
19
19
|
**Constants/Variables:**
|
|
20
20
|
- `__all__: List[str]` - Public API exports including all models and schemas
|
|
@@ -36,6 +36,49 @@ engine = create_engine("sqlite:///example.db")
|
|
|
36
36
|
Base.metadata.create_all(engine)
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
### chat_task_model.py
|
|
40
|
+
**Purpose:** SQLAlchemy model for storing chat tasks with session relationships
|
|
41
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.models.chat_task_model import ChatTaskModel`
|
|
42
|
+
|
|
43
|
+
**Classes:**
|
|
44
|
+
- `ChatTaskModel(Base)` - SQLAlchemy model for chat tasks
|
|
45
|
+
- `id: Column[String]` - Primary key task identifier
|
|
46
|
+
- `session_id: Column[String]` - Foreign key to sessions table with CASCADE delete (indexed)
|
|
47
|
+
- `user_id: Column[String]` - User identifier (indexed)
|
|
48
|
+
- `user_message: Column[Text]` - Optional user message content
|
|
49
|
+
- `message_bubbles: Column[Text]` - Required message bubbles data
|
|
50
|
+
- `task_metadata: Column[Text]` - Optional task metadata
|
|
51
|
+
- `created_time: Column[BigInteger]` - Creation timestamp in epoch milliseconds (indexed)
|
|
52
|
+
- `updated_time: Column[BigInteger]` - Optional update timestamp
|
|
53
|
+
- `session: relationship` - SQLAlchemy relationship to SessionModel
|
|
54
|
+
|
|
55
|
+
**Usage Examples:**
|
|
56
|
+
```python
|
|
57
|
+
from solace_agent_mesh.gateway.http_sse.repository.models.chat_task_model import ChatTaskModel
|
|
58
|
+
from sqlalchemy.orm import sessionmaker
|
|
59
|
+
|
|
60
|
+
# Create a chat task
|
|
61
|
+
chat_task = ChatTaskModel(
|
|
62
|
+
id="task_123",
|
|
63
|
+
session_id="session_456",
|
|
64
|
+
user_id="user_789",
|
|
65
|
+
user_message="Hello, how can you help me?",
|
|
66
|
+
message_bubbles='[{"type": "user", "content": "Hello"}]',
|
|
67
|
+
task_metadata='{"priority": "high"}',
|
|
68
|
+
created_time=1640995200000,
|
|
69
|
+
updated_time=1640995260000
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Add to database
|
|
73
|
+
Session = sessionmaker(bind=engine)
|
|
74
|
+
db_session = Session()
|
|
75
|
+
db_session.add(chat_task)
|
|
76
|
+
db_session.commit()
|
|
77
|
+
|
|
78
|
+
# Access related session
|
|
79
|
+
session = chat_task.session
|
|
80
|
+
```
|
|
81
|
+
|
|
39
82
|
### feedback_model.py
|
|
40
83
|
**Purpose:** SQLAlchemy model for storing user feedback on tasks
|
|
41
84
|
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.models.feedback_model import FeedbackModel`
|
|
@@ -73,60 +116,8 @@ db_session.add(feedback)
|
|
|
73
116
|
db_session.commit()
|
|
74
117
|
```
|
|
75
118
|
|
|
76
|
-
### message_model.py
|
|
77
|
-
**Purpose:** SQLAlchemy model and Pydantic schemas for storing chat messages with session relationships
|
|
78
|
-
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.models.message_model import MessageModel, CreateMessageModel, UpdateMessageModel`
|
|
79
|
-
|
|
80
|
-
**Classes:**
|
|
81
|
-
- `MessageModel(Base)` - SQLAlchemy model for chat messages
|
|
82
|
-
- `id: Column[String]` - Primary key message identifier
|
|
83
|
-
- `session_id: Column[String]` - Foreign key to sessions table with CASCADE delete
|
|
84
|
-
- `message: Column[Text]` - Message content
|
|
85
|
-
- `created_time: Column[BigInteger]` - Creation timestamp (auto-generated)
|
|
86
|
-
- `sender_type: Column[String]` - Type of message sender (max 50 chars)
|
|
87
|
-
- `sender_name: Column[String]` - Name of message sender (max 255 chars)
|
|
88
|
-
- `session: relationship` - SQLAlchemy relationship to SessionModel
|
|
89
|
-
|
|
90
|
-
- `CreateMessageModel(BaseModel)` - Pydantic model for creating messages
|
|
91
|
-
- `id: str` - Message identifier
|
|
92
|
-
- `session_id: str` - Session identifier
|
|
93
|
-
- `message: str` - Message content
|
|
94
|
-
- `sender_type: str` - Sender type
|
|
95
|
-
- `sender_name: str` - Sender name
|
|
96
|
-
- `created_time: int` - Creation timestamp
|
|
97
|
-
|
|
98
|
-
- `UpdateMessageModel(BaseModel)` - Pydantic model for updating messages
|
|
99
|
-
- `message: str` - Updated message content
|
|
100
|
-
- `sender_type: str` - Updated sender type
|
|
101
|
-
- `sender_name: str` - Updated sender name
|
|
102
|
-
|
|
103
|
-
**Usage Examples:**
|
|
104
|
-
```python
|
|
105
|
-
from solace_agent_mesh.gateway.http_sse.repository.models.message_model import MessageModel, CreateMessageModel
|
|
106
|
-
from sqlalchemy.orm import sessionmaker
|
|
107
|
-
|
|
108
|
-
# Create using SQLAlchemy model
|
|
109
|
-
message = MessageModel(
|
|
110
|
-
id="msg_123",
|
|
111
|
-
session_id="session_456",
|
|
112
|
-
message="Hello, world!",
|
|
113
|
-
sender_type="user",
|
|
114
|
-
sender_name="John Doe"
|
|
115
|
-
)
|
|
116
|
-
|
|
117
|
-
# Create using Pydantic model
|
|
118
|
-
create_data = CreateMessageModel(
|
|
119
|
-
id="msg_124",
|
|
120
|
-
session_id="session_456",
|
|
121
|
-
message="How are you?",
|
|
122
|
-
sender_type="user",
|
|
123
|
-
sender_name="John Doe",
|
|
124
|
-
created_time=1640995200000
|
|
125
|
-
)
|
|
126
|
-
```
|
|
127
|
-
|
|
128
119
|
### session_model.py
|
|
129
|
-
**Purpose:** SQLAlchemy model and Pydantic schemas for managing chat sessions with
|
|
120
|
+
**Purpose:** SQLAlchemy model and Pydantic schemas for managing chat sessions with chat task relationships
|
|
130
121
|
**Import:** `from solace_agent_mesh.gateway.http_sse.repository.models.session_model import SessionModel, CreateSessionModel, UpdateSessionModel`
|
|
131
122
|
|
|
132
123
|
**Classes:**
|
|
@@ -137,7 +128,7 @@ create_data = CreateMessageModel(
|
|
|
137
128
|
- `agent_id: Column[String]` - Optional agent identifier
|
|
138
129
|
- `created_time: Column[BigInteger]` - Creation timestamp (auto-generated)
|
|
139
130
|
- `updated_time: Column[BigInteger]` - Last update timestamp (auto-updated)
|
|
140
|
-
- `
|
|
131
|
+
- `chat_tasks: relationship` - SQLAlchemy relationship to ChatTaskModel with cascade delete
|
|
141
132
|
|
|
142
133
|
- `CreateSessionModel(BaseModel)` - Pydantic model for creating sessions
|
|
143
134
|
- `id: str` - Session identifier
|
|
@@ -175,8 +166,8 @@ create_data = CreateSessionModel(
|
|
|
175
166
|
updated_time=1640995200000
|
|
176
167
|
)
|
|
177
168
|
|
|
178
|
-
# Access related
|
|
179
|
-
|
|
169
|
+
# Access related chat tasks
|
|
170
|
+
chat_tasks = session.chat_tasks # Returns list of ChatTaskModel instances
|
|
180
171
|
```
|
|
181
172
|
|
|
182
173
|
### task_event_model.py
|
|
@@ -263,4 +254,4 @@ db_session.commit()
|
|
|
263
254
|
events = task.events # Returns list of TaskEventModel instances
|
|
264
255
|
```
|
|
265
256
|
|
|
266
|
-
# content_hash:
|
|
257
|
+
# content_hash: 65d43bc49dd561efb9955aae2fc39945567e4302c406eea9718ce797d083646c
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SQLAlchemy model for project data.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from sqlalchemy import Column, String, Boolean, BigInteger, Text
|
|
6
|
+
from sqlalchemy.orm import relationship
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
|
|
9
|
+
from .base import Base
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class ProjectModel(Base):
|
|
13
|
+
"""SQLAlchemy model for projects."""
|
|
14
|
+
|
|
15
|
+
__tablename__ = "projects"
|
|
16
|
+
|
|
17
|
+
id = Column(String, primary_key=True)
|
|
18
|
+
name = Column(String, nullable=False)
|
|
19
|
+
user_id = Column(String, nullable=False)
|
|
20
|
+
description = Column(Text, nullable=True)
|
|
21
|
+
system_prompt = Column(Text, nullable=True)
|
|
22
|
+
default_agent_id = Column(String, nullable=True)
|
|
23
|
+
created_at = Column(BigInteger, nullable=False)
|
|
24
|
+
updated_at = Column(BigInteger, nullable=True)
|
|
25
|
+
deleted_at = Column(BigInteger, nullable=True)
|
|
26
|
+
deleted_by = Column(String, nullable=True)
|
|
27
|
+
|
|
28
|
+
# Relationships
|
|
29
|
+
sessions = relationship("SessionModel", back_populates="project")
|
|
30
|
+
project_users = relationship("ProjectUserModel", back_populates="project", cascade="all, delete-orphan")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class CreateProjectModel(BaseModel):
|
|
34
|
+
"""Pydantic model for creating a project."""
|
|
35
|
+
id: str
|
|
36
|
+
name: str
|
|
37
|
+
user_id: str | None = None
|
|
38
|
+
description: str | None = None
|
|
39
|
+
system_prompt: str | None = None
|
|
40
|
+
default_agent_id: str | None = None
|
|
41
|
+
created_at: int
|
|
42
|
+
updated_at: int | None = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class UpdateProjectModel(BaseModel):
|
|
46
|
+
"""Pydantic model for updating a project."""
|
|
47
|
+
name: str | None = None
|
|
48
|
+
description: str | None = None
|
|
49
|
+
system_prompt: str | None = None
|
|
50
|
+
default_agent_id: str | None = None
|
|
51
|
+
updated_at: int
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"""
|
|
2
|
+
SQLAlchemy model for project user access (junction table).
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from sqlalchemy import Column, String, BigInteger, ForeignKey, UniqueConstraint, Enum as SQLEnum
|
|
7
|
+
from sqlalchemy.orm import relationship
|
|
8
|
+
from pydantic import BaseModel, field_validator
|
|
9
|
+
from typing import Literal
|
|
10
|
+
|
|
11
|
+
from .base import Base
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ProjectRole(str, Enum):
|
|
15
|
+
"""Valid roles for project users."""
|
|
16
|
+
OWNER = "owner"
|
|
17
|
+
EDITOR = "editor"
|
|
18
|
+
VIEWER = "viewer"
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ProjectUserModel(Base):
|
|
22
|
+
"""
|
|
23
|
+
SQLAlchemy model for project user access.
|
|
24
|
+
|
|
25
|
+
This junction table tracks which users have access to which projects,
|
|
26
|
+
enabling multi-user collaboration on projects.
|
|
27
|
+
"""
|
|
28
|
+
|
|
29
|
+
__tablename__ = "project_users"
|
|
30
|
+
|
|
31
|
+
id = Column(String, primary_key=True)
|
|
32
|
+
project_id = Column(String, ForeignKey("projects.id", ondelete="CASCADE"), nullable=False)
|
|
33
|
+
user_id = Column(String, nullable=False)
|
|
34
|
+
role = Column(SQLEnum(ProjectRole), nullable=False, default=ProjectRole.VIEWER)
|
|
35
|
+
added_at = Column(BigInteger, nullable=False) # Epoch timestamp in milliseconds
|
|
36
|
+
added_by_user_id = Column(String, nullable=False) # User who granted access
|
|
37
|
+
|
|
38
|
+
# Ensure a user can only be added once per project
|
|
39
|
+
__table_args__ = (
|
|
40
|
+
UniqueConstraint('project_id', 'user_id', name='uq_project_user'),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
# Relationships
|
|
44
|
+
project = relationship("ProjectModel", back_populates="project_users")
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class CreateProjectUserModel(BaseModel):
|
|
48
|
+
"""Pydantic model for creating a project user access record."""
|
|
49
|
+
id: str
|
|
50
|
+
project_id: str
|
|
51
|
+
user_id: str
|
|
52
|
+
role: Literal["owner", "editor", "viewer"] = "viewer"
|
|
53
|
+
added_at: int
|
|
54
|
+
added_by_user_id: str
|
|
55
|
+
|
|
56
|
+
@field_validator('role')
|
|
57
|
+
@classmethod
|
|
58
|
+
def validate_role(cls, v: str) -> str:
|
|
59
|
+
"""Validate that role is one of the allowed values."""
|
|
60
|
+
if v not in [role.value for role in ProjectRole]:
|
|
61
|
+
raise ValueError(f"Role must be one of: {', '.join([role.value for role in ProjectRole])}")
|
|
62
|
+
return v
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class UpdateProjectUserModel(BaseModel):
|
|
66
|
+
"""Pydantic model for updating a project user access record."""
|
|
67
|
+
role: Literal["owner", "editor", "viewer"] | None = None
|
|
68
|
+
|
|
69
|
+
@field_validator('role')
|
|
70
|
+
@classmethod
|
|
71
|
+
def validate_role(cls, v: str | None) -> str | None:
|
|
72
|
+
"""Validate that role is one of the allowed values."""
|
|
73
|
+
if v is not None and v not in [role.value for role in ProjectRole]:
|
|
74
|
+
raise ValueError(f"Role must be one of: {', '.join([role.value for role in ProjectRole])}")
|
|
75
|
+
return v
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
Session SQLAlchemy model and Pydantic models for strongly-typed operations.
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
|
+
from sqlalchemy import BigInteger, Column, String, ForeignKey
|
|
5
6
|
from pydantic import BaseModel
|
|
6
|
-
from sqlalchemy import BigInteger, Column, String
|
|
7
7
|
from sqlalchemy.orm import relationship
|
|
8
8
|
|
|
9
9
|
from ...shared import now_epoch_ms
|
|
@@ -19,15 +19,19 @@ class SessionModel(Base):
|
|
|
19
19
|
name = Column(String, nullable=True)
|
|
20
20
|
user_id = Column(String, nullable=False)
|
|
21
21
|
agent_id = Column(String, nullable=True)
|
|
22
|
+
project_id = Column(String, ForeignKey("projects.id"), nullable=True)
|
|
22
23
|
created_time = Column(BigInteger, nullable=False, default=now_epoch_ms)
|
|
23
24
|
updated_time = Column(
|
|
24
25
|
BigInteger, nullable=False, default=now_epoch_ms, onupdate=now_epoch_ms
|
|
25
26
|
)
|
|
27
|
+
deleted_at = Column(BigInteger, nullable=True)
|
|
28
|
+
deleted_by = Column(String, nullable=True)
|
|
26
29
|
|
|
27
30
|
# Relationship to chat tasks
|
|
28
31
|
chat_tasks = relationship(
|
|
29
32
|
"ChatTaskModel", back_populates="session", cascade="all, delete-orphan"
|
|
30
33
|
)
|
|
34
|
+
project = relationship("ProjectModel", back_populates="sessions")
|
|
31
35
|
|
|
32
36
|
|
|
33
37
|
class CreateSessionModel(BaseModel):
|
|
@@ -36,6 +40,7 @@ class CreateSessionModel(BaseModel):
|
|
|
36
40
|
name: str | None
|
|
37
41
|
user_id: str
|
|
38
42
|
agent_id: str | None
|
|
43
|
+
project_id: str | None = None
|
|
39
44
|
created_time: int
|
|
40
45
|
updated_time: int
|
|
41
46
|
|
|
@@ -44,4 +49,5 @@ class UpdateSessionModel(BaseModel):
|
|
|
44
49
|
"""Pydantic model for updating a session."""
|
|
45
50
|
name: str | None = None
|
|
46
51
|
agent_id: str | None = None
|
|
52
|
+
project_id: str | None = None
|
|
47
53
|
updated_time: int
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Repository implementation for project data access operations.
|
|
3
|
+
"""
|
|
4
|
+
from typing import List, Optional
|
|
5
|
+
import uuid
|
|
6
|
+
|
|
7
|
+
from sqlalchemy.orm import Session as DBSession
|
|
8
|
+
from sqlalchemy import or_
|
|
9
|
+
|
|
10
|
+
from .interfaces import IProjectRepository
|
|
11
|
+
from .models import ProjectModel, ProjectUserModel
|
|
12
|
+
from .entities.project import Project
|
|
13
|
+
from ..routers.dto.requests.project_requests import ProjectFilter
|
|
14
|
+
from ..shared import now_epoch_ms
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ProjectRepository(IProjectRepository):
|
|
18
|
+
"""SQLAlchemy implementation of project repository."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, db: DBSession):
|
|
21
|
+
self.db = db
|
|
22
|
+
|
|
23
|
+
def create_project(self, name: str, user_id: str, description: Optional[str] = None,
|
|
24
|
+
system_prompt: Optional[str] = None, default_agent_id: Optional[str] = None) -> Project:
|
|
25
|
+
"""Create a new user project."""
|
|
26
|
+
model = ProjectModel(
|
|
27
|
+
id=str(uuid.uuid4()),
|
|
28
|
+
name=name,
|
|
29
|
+
user_id=user_id,
|
|
30
|
+
description=description,
|
|
31
|
+
system_prompt=system_prompt,
|
|
32
|
+
default_agent_id=default_agent_id,
|
|
33
|
+
created_at=now_epoch_ms(),
|
|
34
|
+
)
|
|
35
|
+
self.db.add(model)
|
|
36
|
+
self.db.flush()
|
|
37
|
+
self.db.refresh(model)
|
|
38
|
+
return self._model_to_entity(model)
|
|
39
|
+
|
|
40
|
+
def get_user_projects(self, user_id: str) -> List[Project]:
|
|
41
|
+
"""
|
|
42
|
+
Get all projects owned by a specific user.
|
|
43
|
+
|
|
44
|
+
Note: This returns only projects where the user is the owner (user_id matches).
|
|
45
|
+
For projects the user has access to via project_users table, use get_accessible_projects().
|
|
46
|
+
"""
|
|
47
|
+
models = self.db.query(ProjectModel).filter(
|
|
48
|
+
ProjectModel.user_id == user_id,
|
|
49
|
+
ProjectModel.deleted_at.is_(None) # Exclude soft-deleted projects
|
|
50
|
+
).all()
|
|
51
|
+
return [self._model_to_entity(model) for model in models]
|
|
52
|
+
|
|
53
|
+
def get_accessible_projects(self, user_id: str) -> List[Project]:
|
|
54
|
+
"""
|
|
55
|
+
Get all projects accessible by a user (owned or shared).
|
|
56
|
+
|
|
57
|
+
This includes:
|
|
58
|
+
- Projects owned by the user (user_id matches)
|
|
59
|
+
- Projects shared with the user (via project_users table)
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
user_id: The user ID
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
List[Project]: List of accessible projects
|
|
66
|
+
"""
|
|
67
|
+
# Query for projects where user is owner OR has access via project_users
|
|
68
|
+
models = self.db.query(ProjectModel).outerjoin(
|
|
69
|
+
ProjectUserModel,
|
|
70
|
+
ProjectModel.id == ProjectUserModel.project_id
|
|
71
|
+
).filter(
|
|
72
|
+
ProjectModel.deleted_at.is_(None), # Exclude soft-deleted projects
|
|
73
|
+
or_(
|
|
74
|
+
ProjectModel.user_id == user_id,
|
|
75
|
+
ProjectUserModel.user_id == user_id
|
|
76
|
+
)
|
|
77
|
+
).distinct().all()
|
|
78
|
+
|
|
79
|
+
return [self._model_to_entity(model) for model in models]
|
|
80
|
+
|
|
81
|
+
def get_filtered_projects(self, project_filter: ProjectFilter) -> List[Project]:
|
|
82
|
+
"""Get projects based on filter criteria."""
|
|
83
|
+
query = self.db.query(ProjectModel).filter(
|
|
84
|
+
ProjectModel.deleted_at.is_(None) # Exclude soft-deleted projects
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
if project_filter.user_id is not None:
|
|
88
|
+
query = query.filter(ProjectModel.user_id == project_filter.user_id)
|
|
89
|
+
|
|
90
|
+
models = query.all()
|
|
91
|
+
return [self._model_to_entity(model) for model in models]
|
|
92
|
+
|
|
93
|
+
def get_by_id(self, project_id: str, user_id: str) -> Optional[Project]:
|
|
94
|
+
"""
|
|
95
|
+
Get a project by its ID, ensuring user access.
|
|
96
|
+
|
|
97
|
+
This checks if the user is the owner OR has access via project_users table.
|
|
98
|
+
"""
|
|
99
|
+
model = self.db.query(ProjectModel).outerjoin(
|
|
100
|
+
ProjectUserModel,
|
|
101
|
+
ProjectModel.id == ProjectUserModel.project_id
|
|
102
|
+
).filter(
|
|
103
|
+
ProjectModel.id == project_id,
|
|
104
|
+
ProjectModel.deleted_at.is_(None), # Exclude soft-deleted projects
|
|
105
|
+
or_(
|
|
106
|
+
ProjectModel.user_id == user_id,
|
|
107
|
+
ProjectUserModel.user_id == user_id
|
|
108
|
+
)
|
|
109
|
+
).first()
|
|
110
|
+
|
|
111
|
+
return self._model_to_entity(model) if model else None
|
|
112
|
+
|
|
113
|
+
def update(self, project_id: str, user_id: str, update_data: dict) -> Optional[Project]:
|
|
114
|
+
"""Update a project with the given data, ensuring user access."""
|
|
115
|
+
model = self.db.query(ProjectModel).filter(
|
|
116
|
+
ProjectModel.id == project_id,
|
|
117
|
+
ProjectModel.user_id == user_id, # Only allow updates to user's own projects
|
|
118
|
+
ProjectModel.deleted_at.is_(None) # Exclude soft-deleted projects
|
|
119
|
+
).first()
|
|
120
|
+
|
|
121
|
+
if not model:
|
|
122
|
+
return None
|
|
123
|
+
|
|
124
|
+
for field, value in update_data.items():
|
|
125
|
+
if hasattr(model, field):
|
|
126
|
+
setattr(model, field, value)
|
|
127
|
+
|
|
128
|
+
model.updated_at = now_epoch_ms()
|
|
129
|
+
self.db.flush()
|
|
130
|
+
self.db.refresh(model)
|
|
131
|
+
return self._model_to_entity(model)
|
|
132
|
+
|
|
133
|
+
def delete(self, project_id: str, user_id: str) -> bool:
|
|
134
|
+
"""Delete a project by its ID, ensuring user access."""
|
|
135
|
+
result = self.db.query(ProjectModel).filter(
|
|
136
|
+
ProjectModel.id == project_id,
|
|
137
|
+
ProjectModel.user_id == user_id # Only allow deletion of user's own projects
|
|
138
|
+
).delete()
|
|
139
|
+
self.db.flush()
|
|
140
|
+
return result > 0
|
|
141
|
+
|
|
142
|
+
def soft_delete(self, project_id: str, user_id: str) -> bool:
|
|
143
|
+
"""Soft delete a project by its ID, ensuring user access."""
|
|
144
|
+
model = self.db.query(ProjectModel).filter(
|
|
145
|
+
ProjectModel.id == project_id,
|
|
146
|
+
ProjectModel.user_id == user_id, # Only allow deletion of user's own projects
|
|
147
|
+
ProjectModel.deleted_at.is_(None) # Only delete if not already deleted
|
|
148
|
+
).first()
|
|
149
|
+
|
|
150
|
+
if not model:
|
|
151
|
+
return False
|
|
152
|
+
|
|
153
|
+
model.deleted_at = now_epoch_ms()
|
|
154
|
+
model.deleted_by = user_id
|
|
155
|
+
model.updated_at = now_epoch_ms()
|
|
156
|
+
self.db.flush()
|
|
157
|
+
return True
|
|
158
|
+
|
|
159
|
+
def _model_to_entity(self, model: ProjectModel) -> Project:
|
|
160
|
+
"""Convert SQLAlchemy model to domain entity."""
|
|
161
|
+
return Project(
|
|
162
|
+
id=model.id,
|
|
163
|
+
name=model.name,
|
|
164
|
+
user_id=model.user_id,
|
|
165
|
+
description=model.description,
|
|
166
|
+
system_prompt=model.system_prompt,
|
|
167
|
+
default_agent_id=model.default_agent_id,
|
|
168
|
+
created_at=model.created_at,
|
|
169
|
+
updated_at=model.updated_at,
|
|
170
|
+
deleted_at=model.deleted_at,
|
|
171
|
+
deleted_by=model.deleted_by,
|
|
172
|
+
)
|