solace-agent-mesh 1.6.3__py3-none-any.whl → 1.7.1__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/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.f213fe0c.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 +4 -4
- 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-1762283454666.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1762283454666.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 +0 -14
- solace_agent_mesh/gateway/http_sse/component.py +17 -56
- 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 +23 -5
- 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.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/METADATA +3 -5
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/RECORD +218 -175
- 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.3b883666.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.ed05b14d.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.a8a75e0b.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1761744323675.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1761744323675.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.ed05b14d.js.LICENSE.txt → main.f213fe0c.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from typing import Optional
|
|
2
3
|
from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
|
|
3
4
|
from sqlalchemy.orm import Session
|
|
4
5
|
|
|
@@ -10,6 +11,8 @@ from ..shared.response_utils import create_data_response
|
|
|
10
11
|
from .dto.requests.session_requests import (
|
|
11
12
|
GetSessionRequest,
|
|
12
13
|
UpdateSessionRequest,
|
|
14
|
+
MoveSessionRequest,
|
|
15
|
+
SearchSessionsRequest,
|
|
13
16
|
)
|
|
14
17
|
from .dto.requests.task_requests import SaveTaskRequest
|
|
15
18
|
from .dto.responses.session_responses import SessionResponse
|
|
@@ -24,6 +27,7 @@ SESSION_NOT_FOUND_MSG = "Session not found."
|
|
|
24
27
|
|
|
25
28
|
@router.get("/sessions", response_model=PaginatedResponse[SessionResponse])
|
|
26
29
|
async def get_all_sessions(
|
|
30
|
+
project_id: Optional[str] = Query(default=None, alias="project_id"),
|
|
27
31
|
page_number: int = Query(default=1, ge=1, alias="pageNumber"),
|
|
28
32
|
page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
|
|
29
33
|
db: Session = Depends(get_db),
|
|
@@ -31,10 +35,14 @@ async def get_all_sessions(
|
|
|
31
35
|
session_service: SessionService = Depends(get_session_business_service),
|
|
32
36
|
):
|
|
33
37
|
user_id = user.get("id")
|
|
38
|
+
log_msg = f"User '{user_id}' is listing sessions with pagination (page={page_number}, size={page_size})"
|
|
39
|
+
if project_id:
|
|
40
|
+
log_msg += f" filtered by project_id={project_id}"
|
|
41
|
+
log.info(log_msg)
|
|
34
42
|
|
|
35
43
|
try:
|
|
36
44
|
pagination = PaginationParams(page_number=page_number, page_size=page_size)
|
|
37
|
-
paginated_response = session_service.get_user_sessions(db, user_id, pagination)
|
|
45
|
+
paginated_response = session_service.get_user_sessions(db, user_id, pagination, project_id=project_id)
|
|
38
46
|
|
|
39
47
|
session_responses = []
|
|
40
48
|
for session_domain in paginated_response.data:
|
|
@@ -43,6 +51,8 @@ async def get_all_sessions(
|
|
|
43
51
|
user_id=session_domain.user_id,
|
|
44
52
|
name=session_domain.name,
|
|
45
53
|
agent_id=session_domain.agent_id,
|
|
54
|
+
project_id=session_domain.project_id,
|
|
55
|
+
project_name=session_domain.project_name,
|
|
46
56
|
created_time=session_domain.created_time,
|
|
47
57
|
updated_time=session_domain.updated_time,
|
|
48
58
|
)
|
|
@@ -58,6 +68,63 @@ async def get_all_sessions(
|
|
|
58
68
|
) from e
|
|
59
69
|
|
|
60
70
|
|
|
71
|
+
@router.get("/sessions/search", response_model=PaginatedResponse[SessionResponse])
|
|
72
|
+
async def search_sessions(
|
|
73
|
+
query: str = Query(..., min_length=1, description="Search query"),
|
|
74
|
+
project_id: Optional[str] = Query(default=None, alias="projectId"),
|
|
75
|
+
page_number: int = Query(default=1, ge=1, alias="pageNumber"),
|
|
76
|
+
page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
|
|
77
|
+
db: Session = Depends(get_db),
|
|
78
|
+
user: dict = Depends(get_current_user),
|
|
79
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
80
|
+
):
|
|
81
|
+
"""
|
|
82
|
+
Search sessions by name or content.
|
|
83
|
+
"""
|
|
84
|
+
user_id = user.get("id")
|
|
85
|
+
log.info(
|
|
86
|
+
"User %s searching sessions with query '%s' (page=%d, size=%d)",
|
|
87
|
+
user_id,
|
|
88
|
+
query,
|
|
89
|
+
page_number,
|
|
90
|
+
page_size,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
try:
|
|
94
|
+
pagination = PaginationParams(page_number=page_number, page_size=page_size)
|
|
95
|
+
paginated_response = session_service.search_sessions(
|
|
96
|
+
db, user_id, query, pagination, project_id=project_id
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
session_responses = []
|
|
100
|
+
for session_domain in paginated_response.data:
|
|
101
|
+
session_response = SessionResponse(
|
|
102
|
+
id=session_domain.id,
|
|
103
|
+
user_id=session_domain.user_id,
|
|
104
|
+
name=session_domain.name,
|
|
105
|
+
agent_id=session_domain.agent_id,
|
|
106
|
+
project_id=session_domain.project_id,
|
|
107
|
+
project_name=session_domain.project_name,
|
|
108
|
+
created_time=session_domain.created_time,
|
|
109
|
+
updated_time=session_domain.updated_time,
|
|
110
|
+
)
|
|
111
|
+
session_responses.append(session_response)
|
|
112
|
+
|
|
113
|
+
return PaginatedResponse(data=session_responses, meta=paginated_response.meta)
|
|
114
|
+
|
|
115
|
+
except ValueError as e:
|
|
116
|
+
log.warning("Validation error searching sessions: %s", e)
|
|
117
|
+
raise HTTPException(
|
|
118
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
|
|
119
|
+
) from e
|
|
120
|
+
except Exception as e:
|
|
121
|
+
log.error("Error searching sessions for user %s: %s", user_id, e)
|
|
122
|
+
raise HTTPException(
|
|
123
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
124
|
+
detail="Failed to search sessions",
|
|
125
|
+
) from e
|
|
126
|
+
|
|
127
|
+
|
|
61
128
|
@router.get("/sessions/{session_id}", response_model=DataResponse[SessionResponse])
|
|
62
129
|
async def get_session(
|
|
63
130
|
session_id: str,
|
|
@@ -95,6 +162,7 @@ async def get_session(
|
|
|
95
162
|
user_id=session_domain.user_id,
|
|
96
163
|
name=session_domain.name,
|
|
97
164
|
agent_id=session_domain.agent_id,
|
|
165
|
+
project_id=session_domain.project_id,
|
|
98
166
|
created_time=session_domain.created_time,
|
|
99
167
|
updated_time=session_domain.updated_time,
|
|
100
168
|
)
|
|
@@ -399,6 +467,7 @@ async def update_session_name(
|
|
|
399
467
|
user_id=updated_domain.user_id,
|
|
400
468
|
name=updated_domain.name,
|
|
401
469
|
agent_id=updated_domain.agent_id,
|
|
470
|
+
project_id=updated_domain.project_id,
|
|
402
471
|
created_time=updated_domain.created_time,
|
|
403
472
|
updated_time=updated_domain.updated_time,
|
|
404
473
|
)
|
|
@@ -430,8 +499,11 @@ async def delete_session(
|
|
|
430
499
|
user: dict = Depends(get_current_user),
|
|
431
500
|
session_service: SessionService = Depends(get_session_business_service),
|
|
432
501
|
):
|
|
502
|
+
"""
|
|
503
|
+
Soft delete a session (marks as deleted without removing from database).
|
|
504
|
+
"""
|
|
433
505
|
user_id = user.get("id")
|
|
434
|
-
log.info("User %s attempting to delete session %s", user_id, session_id)
|
|
506
|
+
log.info("User %s attempting to soft delete session %s", user_id, session_id)
|
|
435
507
|
|
|
436
508
|
try:
|
|
437
509
|
if (
|
|
@@ -452,7 +524,7 @@ async def delete_session(
|
|
|
452
524
|
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
453
525
|
)
|
|
454
526
|
|
|
455
|
-
log.info("Session %s deleted successfully", session_id)
|
|
527
|
+
log.info("Session %s soft deleted successfully", session_id)
|
|
456
528
|
|
|
457
529
|
except HTTPException:
|
|
458
530
|
raise
|
|
@@ -472,3 +544,82 @@ async def delete_session(
|
|
|
472
544
|
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
473
545
|
detail="Failed to delete session",
|
|
474
546
|
) from e
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
@router.patch("/sessions/{session_id}/project", response_model=SessionResponse)
|
|
550
|
+
async def move_session_to_project(
|
|
551
|
+
session_id: str,
|
|
552
|
+
request: MoveSessionRequest,
|
|
553
|
+
db: Session = Depends(get_db),
|
|
554
|
+
user: dict = Depends(get_current_user),
|
|
555
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
556
|
+
):
|
|
557
|
+
"""
|
|
558
|
+
Move a session to a different project or remove from project.
|
|
559
|
+
"""
|
|
560
|
+
user_id = user.get("id")
|
|
561
|
+
log.info(
|
|
562
|
+
"User %s attempting to move session %s to project %s",
|
|
563
|
+
user_id,
|
|
564
|
+
session_id,
|
|
565
|
+
request.project_id,
|
|
566
|
+
)
|
|
567
|
+
|
|
568
|
+
try:
|
|
569
|
+
if (
|
|
570
|
+
not session_id
|
|
571
|
+
or session_id.strip() == ""
|
|
572
|
+
or session_id in ["null", "undefined"]
|
|
573
|
+
):
|
|
574
|
+
raise HTTPException(
|
|
575
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
updated_session = session_service.move_session_to_project(
|
|
579
|
+
db=db,
|
|
580
|
+
session_id=session_id,
|
|
581
|
+
user_id=user_id,
|
|
582
|
+
new_project_id=request.project_id,
|
|
583
|
+
)
|
|
584
|
+
|
|
585
|
+
if not updated_session:
|
|
586
|
+
raise HTTPException(
|
|
587
|
+
status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
log.info(
|
|
591
|
+
"Session %s moved to project %s successfully",
|
|
592
|
+
session_id,
|
|
593
|
+
request.project_id or "None",
|
|
594
|
+
)
|
|
595
|
+
|
|
596
|
+
return SessionResponse(
|
|
597
|
+
id=updated_session.id,
|
|
598
|
+
user_id=updated_session.user_id,
|
|
599
|
+
name=updated_session.name,
|
|
600
|
+
agent_id=updated_session.agent_id,
|
|
601
|
+
project_id=updated_session.project_id,
|
|
602
|
+
created_time=updated_session.created_time,
|
|
603
|
+
updated_time=updated_session.updated_time,
|
|
604
|
+
)
|
|
605
|
+
|
|
606
|
+
except HTTPException:
|
|
607
|
+
raise
|
|
608
|
+
except ValueError as e:
|
|
609
|
+
log.warning("Validation error moving session %s: %s", session_id, e)
|
|
610
|
+
raise HTTPException(
|
|
611
|
+
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
|
|
612
|
+
) from e
|
|
613
|
+
except Exception as e:
|
|
614
|
+
log.error(
|
|
615
|
+
"Error moving session %s for user %s: %s",
|
|
616
|
+
session_id,
|
|
617
|
+
user_id,
|
|
618
|
+
e,
|
|
619
|
+
)
|
|
620
|
+
raise HTTPException(
|
|
621
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
622
|
+
detail="Failed to move session",
|
|
623
|
+
) from e
|
|
624
|
+
|
|
625
|
+
|
|
@@ -3,7 +3,7 @@ API Router for submitting and managing tasks to agents.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import logging
|
|
6
|
-
from datetime import datetime
|
|
6
|
+
from datetime import datetime, timezone
|
|
7
7
|
from typing import TYPE_CHECKING
|
|
8
8
|
|
|
9
9
|
import yaml
|
|
@@ -18,9 +18,18 @@ from fastapi import APIRouter, Depends, HTTPException, Response, status
|
|
|
18
18
|
from fastapi import Request as FastAPIRequest
|
|
19
19
|
from sqlalchemy.orm import Session as DBSession
|
|
20
20
|
|
|
21
|
+
from ....gateway.http_sse.services.project_service import ProjectService
|
|
22
|
+
|
|
23
|
+
from ....agent.utils.artifact_helpers import (
|
|
24
|
+
get_artifact_info_list,
|
|
25
|
+
load_artifact_content_or_metadata,
|
|
26
|
+
save_artifact_with_metadata,
|
|
27
|
+
)
|
|
28
|
+
|
|
21
29
|
from ....common import a2a
|
|
22
30
|
from ....gateway.http_sse.dependencies import (
|
|
23
31
|
get_db,
|
|
32
|
+
get_project_service_optional,
|
|
24
33
|
get_sac_component,
|
|
25
34
|
get_session_business_service,
|
|
26
35
|
get_session_manager,
|
|
@@ -46,20 +55,231 @@ router = APIRouter()
|
|
|
46
55
|
log = logging.getLogger(__name__)
|
|
47
56
|
|
|
48
57
|
|
|
58
|
+
async def _inject_project_context(
|
|
59
|
+
project_id: str,
|
|
60
|
+
message_text: str,
|
|
61
|
+
user_id: str,
|
|
62
|
+
session_id: str,
|
|
63
|
+
project_service: ProjectService,
|
|
64
|
+
component: "WebUIBackendComponent",
|
|
65
|
+
log_prefix: str,
|
|
66
|
+
inject_full_context: bool = True,
|
|
67
|
+
) -> str:
|
|
68
|
+
"""
|
|
69
|
+
Helper function to inject project context and copy artifacts to session.
|
|
70
|
+
|
|
71
|
+
Args:
|
|
72
|
+
inject_full_context: If True, injects full project context (name, description, instructions).
|
|
73
|
+
If False, only copies new artifacts without modifying message text.
|
|
74
|
+
This allows existing sessions to get new project files without
|
|
75
|
+
re-injecting the full context on every message.
|
|
76
|
+
|
|
77
|
+
Returns the modified message text with project context injected (if inject_full_context=True).
|
|
78
|
+
"""
|
|
79
|
+
if not project_id or not message_text:
|
|
80
|
+
return message_text
|
|
81
|
+
|
|
82
|
+
from ....gateway.http_sse.dependencies import SessionLocal
|
|
83
|
+
|
|
84
|
+
if SessionLocal is None:
|
|
85
|
+
log.warning("%sProject context injection skipped: database not configured", log_prefix)
|
|
86
|
+
return message_text
|
|
87
|
+
|
|
88
|
+
db = SessionLocal()
|
|
89
|
+
try:
|
|
90
|
+
project = project_service.get_project(db, project_id, user_id)
|
|
91
|
+
if not project:
|
|
92
|
+
return message_text
|
|
93
|
+
|
|
94
|
+
context_parts = []
|
|
95
|
+
|
|
96
|
+
# Only inject full context for new sessions
|
|
97
|
+
if inject_full_context:
|
|
98
|
+
# Start with clear workspace framing
|
|
99
|
+
context_parts.append(f'You are working in the project workspace: "{project.name}"')
|
|
100
|
+
|
|
101
|
+
# Add system prompt if exists
|
|
102
|
+
if project.system_prompt and project.system_prompt.strip():
|
|
103
|
+
context_parts.append(f"\n{project.system_prompt.strip()}")
|
|
104
|
+
|
|
105
|
+
# Add project description if exists
|
|
106
|
+
if project.description and project.description.strip():
|
|
107
|
+
context_parts.append(f"\nProject Description: {project.description.strip()}")
|
|
108
|
+
|
|
109
|
+
# Always copy project artifacts to session (for both new and existing sessions)
|
|
110
|
+
# This ensures new project files are available to existing sessions
|
|
111
|
+
artifact_service = component.get_shared_artifact_service()
|
|
112
|
+
if artifact_service:
|
|
113
|
+
try:
|
|
114
|
+
source_user_id = project.user_id
|
|
115
|
+
project_artifacts_session_id = f"project-{project.id}"
|
|
116
|
+
|
|
117
|
+
log.info("%sChecking for artifacts in project %s (storage session: %s)", log_prefix, project.id, project_artifacts_session_id)
|
|
118
|
+
|
|
119
|
+
project_artifacts = await get_artifact_info_list(
|
|
120
|
+
artifact_service=artifact_service,
|
|
121
|
+
app_name=project_service.app_name,
|
|
122
|
+
user_id=source_user_id,
|
|
123
|
+
session_id=project_artifacts_session_id,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
if project_artifacts:
|
|
127
|
+
log.info("%sFound %d artifacts in project %s to process.", log_prefix, len(project_artifacts), project.id)
|
|
128
|
+
|
|
129
|
+
# Get list of artifacts already in session to avoid re-copying
|
|
130
|
+
try:
|
|
131
|
+
session_artifacts = await get_artifact_info_list(
|
|
132
|
+
artifact_service=artifact_service,
|
|
133
|
+
app_name=project_service.app_name,
|
|
134
|
+
user_id=user_id,
|
|
135
|
+
session_id=session_id,
|
|
136
|
+
)
|
|
137
|
+
session_artifact_names = {art.filename for art in session_artifacts}
|
|
138
|
+
log.debug("%sSession %s currently has %d artifacts", log_prefix, session_id, len(session_artifact_names))
|
|
139
|
+
except Exception as e:
|
|
140
|
+
log.warning("%sFailed to get session artifacts, will copy all project artifacts: %s", log_prefix, e)
|
|
141
|
+
session_artifact_names = set()
|
|
142
|
+
|
|
143
|
+
all_artifact_descriptions = [] # For new sessions - all files
|
|
144
|
+
new_artifact_descriptions = [] # For existing sessions - only new files
|
|
145
|
+
artifacts_copied = 0
|
|
146
|
+
|
|
147
|
+
for artifact_info in project_artifacts:
|
|
148
|
+
# Build description for all artifacts (for new sessions)
|
|
149
|
+
desc_str = f"- {artifact_info.filename}"
|
|
150
|
+
if artifact_info.description:
|
|
151
|
+
desc_str += f": {artifact_info.description}"
|
|
152
|
+
all_artifact_descriptions.append(desc_str)
|
|
153
|
+
|
|
154
|
+
# Skip if artifact already exists in session (any source)
|
|
155
|
+
if artifact_info.filename in session_artifact_names:
|
|
156
|
+
log.debug("%sSkipping artifact %s - already exists in session", log_prefix, artifact_info.filename)
|
|
157
|
+
continue
|
|
158
|
+
|
|
159
|
+
# Track new artifacts for existing sessions
|
|
160
|
+
new_artifact_descriptions.append(desc_str)
|
|
161
|
+
|
|
162
|
+
log.info("%sCopying new artifact %s to session %s", log_prefix, artifact_info.filename, session_id)
|
|
163
|
+
|
|
164
|
+
try:
|
|
165
|
+
# Load artifact content from project storage
|
|
166
|
+
loaded_artifact = await load_artifact_content_or_metadata(
|
|
167
|
+
artifact_service=artifact_service,
|
|
168
|
+
app_name=project_service.app_name,
|
|
169
|
+
user_id=source_user_id,
|
|
170
|
+
session_id=project_artifacts_session_id,
|
|
171
|
+
filename=artifact_info.filename,
|
|
172
|
+
return_raw_bytes=True,
|
|
173
|
+
version="latest"
|
|
174
|
+
)
|
|
175
|
+
|
|
176
|
+
# Load the full metadata separately
|
|
177
|
+
loaded_metadata = await load_artifact_content_or_metadata(
|
|
178
|
+
artifact_service=artifact_service,
|
|
179
|
+
app_name=project_service.app_name,
|
|
180
|
+
user_id=source_user_id,
|
|
181
|
+
session_id=project_artifacts_session_id,
|
|
182
|
+
filename=artifact_info.filename,
|
|
183
|
+
load_metadata_only=True,
|
|
184
|
+
version="latest"
|
|
185
|
+
)
|
|
186
|
+
|
|
187
|
+
# Save a copy to the current chat session
|
|
188
|
+
if loaded_artifact.get("status") == "success":
|
|
189
|
+
full_metadata = loaded_metadata.get("metadata", {}) if loaded_metadata.get("status") == "success" else {}
|
|
190
|
+
|
|
191
|
+
# Ensure the source is always set for copied project artifacts
|
|
192
|
+
full_metadata["source"] = "project"
|
|
193
|
+
|
|
194
|
+
await save_artifact_with_metadata(
|
|
195
|
+
artifact_service=artifact_service,
|
|
196
|
+
app_name=project_service.app_name,
|
|
197
|
+
user_id=user_id,
|
|
198
|
+
session_id=session_id,
|
|
199
|
+
filename=artifact_info.filename,
|
|
200
|
+
content_bytes=loaded_artifact.get("raw_bytes"),
|
|
201
|
+
mime_type=loaded_artifact.get("mime_type"),
|
|
202
|
+
metadata_dict=full_metadata,
|
|
203
|
+
timestamp=datetime.now(timezone.utc),
|
|
204
|
+
)
|
|
205
|
+
artifacts_copied += 1
|
|
206
|
+
log.info("%sSuccessfully copied artifact %s to session", log_prefix, artifact_info.filename)
|
|
207
|
+
else:
|
|
208
|
+
log.warning("%sFailed to load artifact %s: %s", log_prefix, artifact_info.filename, loaded_artifact.get("status"))
|
|
209
|
+
except Exception as e:
|
|
210
|
+
log.error("%sError copying artifact %s to session: %s", log_prefix, artifact_info.filename, e)
|
|
211
|
+
# Continue with other artifacts even if one fails
|
|
212
|
+
|
|
213
|
+
# Add artifact descriptions to context
|
|
214
|
+
if inject_full_context and all_artifact_descriptions:
|
|
215
|
+
# New session: show all project files
|
|
216
|
+
artifacts_context = (
|
|
217
|
+
"\nFiles in Session:\n"
|
|
218
|
+
"The following files are available in your session and can be viewed using your tools if required:\n"
|
|
219
|
+
+ "\n".join(all_artifact_descriptions)
|
|
220
|
+
)
|
|
221
|
+
context_parts.append(artifacts_context)
|
|
222
|
+
elif not inject_full_context and new_artifact_descriptions:
|
|
223
|
+
# Existing session: notify about newly added files
|
|
224
|
+
new_files_context = (
|
|
225
|
+
"\nNew Files Added to Project:\n"
|
|
226
|
+
"The following files have been added to the project and are now available in your session:\n"
|
|
227
|
+
+ "\n".join(new_artifact_descriptions)
|
|
228
|
+
)
|
|
229
|
+
context_parts.append(new_files_context)
|
|
230
|
+
|
|
231
|
+
if artifacts_copied > 0:
|
|
232
|
+
log.info("%sCopied %d new artifacts to session %s.", log_prefix, artifacts_copied, session_id)
|
|
233
|
+
else:
|
|
234
|
+
log.debug("%sNo new artifacts to copy to session %s.", log_prefix, session_id)
|
|
235
|
+
else:
|
|
236
|
+
log.info("%sNo artifacts found in project %s to copy.", log_prefix, project.id)
|
|
237
|
+
|
|
238
|
+
except Exception as e:
|
|
239
|
+
log.warning("%sFailed to copy project artifacts to session: %s", log_prefix, e)
|
|
240
|
+
# Do not fail the entire request, just log the warning
|
|
241
|
+
|
|
242
|
+
# Inject all gathered context into the message, ending with user query
|
|
243
|
+
# Only modify message text if we're injecting full context (new sessions)
|
|
244
|
+
modified_message_text = message_text
|
|
245
|
+
if context_parts:
|
|
246
|
+
project_context = "\n".join(context_parts)
|
|
247
|
+
modified_message_text = f"{project_context}\n\nUSER QUERY:\n{message_text}"
|
|
248
|
+
log.info("%sInjected full project context for project: %s", log_prefix, project_id)
|
|
249
|
+
else:
|
|
250
|
+
log.debug("%sSkipped full context injection for existing session, but ensured new artifacts are copied", log_prefix)
|
|
251
|
+
|
|
252
|
+
return modified_message_text
|
|
253
|
+
|
|
254
|
+
except Exception as e:
|
|
255
|
+
log.warning("%sFailed to inject project context: %s", log_prefix, e)
|
|
256
|
+
# Continue without injection - don't fail the request
|
|
257
|
+
return message_text
|
|
258
|
+
finally:
|
|
259
|
+
db.close()
|
|
260
|
+
|
|
261
|
+
|
|
49
262
|
async def _submit_task(
|
|
50
263
|
request: FastAPIRequest,
|
|
51
264
|
payload: SendMessageRequest | SendStreamingMessageRequest,
|
|
52
265
|
session_manager: SessionManager,
|
|
53
266
|
component: "WebUIBackendComponent",
|
|
267
|
+
project_service: ProjectService | None,
|
|
54
268
|
is_streaming: bool,
|
|
55
269
|
session_service: SessionService | None = None,
|
|
56
270
|
):
|
|
57
|
-
"""
|
|
271
|
+
"""
|
|
272
|
+
Helper to submit a task, handling both streaming and non-streaming cases.
|
|
273
|
+
|
|
274
|
+
Also handles project context injection.
|
|
275
|
+
"""
|
|
58
276
|
log_prefix = f"[POST /api/v1/message:{'stream' if is_streaming else 'send'}] "
|
|
59
277
|
|
|
60
278
|
agent_name = None
|
|
279
|
+
project_id = None
|
|
61
280
|
if payload.params and payload.params.message and payload.params.message.metadata:
|
|
62
281
|
agent_name = payload.params.message.metadata.get("agent_name")
|
|
282
|
+
project_id = payload.params.message.metadata.get("project_id")
|
|
63
283
|
|
|
64
284
|
if not agent_name:
|
|
65
285
|
raise HTTPException(
|
|
@@ -99,6 +319,21 @@ async def _submit_task(
|
|
|
99
319
|
user_id = user_identity.get("id")
|
|
100
320
|
from ....gateway.http_sse.dependencies import SessionLocal
|
|
101
321
|
|
|
322
|
+
# If project_id not in metadata, check if session has a project_id in database
|
|
323
|
+
# This handles cases where sessions are moved to projects after creation
|
|
324
|
+
if not project_id and session_service and frontend_session_id:
|
|
325
|
+
if SessionLocal is not None:
|
|
326
|
+
db = SessionLocal()
|
|
327
|
+
try:
|
|
328
|
+
session_details = session_service.get_session_details(db, frontend_session_id, user_id)
|
|
329
|
+
if session_details and session_details.project_id:
|
|
330
|
+
project_id = session_details.project_id
|
|
331
|
+
log.info("%sFound project_id %s from session database for session %s", log_prefix, project_id, frontend_session_id)
|
|
332
|
+
except Exception as e:
|
|
333
|
+
log.warning("%sFailed to lookup session project_id: %s", log_prefix, e)
|
|
334
|
+
finally:
|
|
335
|
+
db.close()
|
|
336
|
+
|
|
102
337
|
if frontend_session_id:
|
|
103
338
|
session_id = frontend_session_id
|
|
104
339
|
log.info(
|
|
@@ -123,6 +358,7 @@ async def _submit_task(
|
|
|
123
358
|
user_id=user_id,
|
|
124
359
|
agent_id=agent_name,
|
|
125
360
|
session_id=session_id,
|
|
361
|
+
project_id=project_id,
|
|
126
362
|
)
|
|
127
363
|
db.commit()
|
|
128
364
|
log.debug(
|
|
@@ -140,8 +376,60 @@ async def _submit_task(
|
|
|
140
376
|
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
141
377
|
)
|
|
142
378
|
|
|
143
|
-
#
|
|
144
|
-
|
|
379
|
+
# Extract message text and apply project context injection
|
|
380
|
+
message_text = ""
|
|
381
|
+
if payload.params and payload.params.message:
|
|
382
|
+
parts = a2a.get_parts_from_message(payload.params.message)
|
|
383
|
+
for part in parts:
|
|
384
|
+
if hasattr(part, "text"):
|
|
385
|
+
message_text = part.text
|
|
386
|
+
break
|
|
387
|
+
|
|
388
|
+
# Project context injection - always inject for project sessions to ensure new files are available
|
|
389
|
+
# Skip if project_service is None (persistence disabled)
|
|
390
|
+
modified_message = payload.params.message
|
|
391
|
+
if project_service and project_id and message_text:
|
|
392
|
+
# Inject context for new sessions (includes full context + artifact copy)
|
|
393
|
+
# For existing sessions, only copy new artifacts without re-injecting full context
|
|
394
|
+
should_inject_full_context = not frontend_session_id
|
|
395
|
+
|
|
396
|
+
modified_message_text = await _inject_project_context(
|
|
397
|
+
project_id=project_id,
|
|
398
|
+
message_text=message_text,
|
|
399
|
+
user_id=user_id,
|
|
400
|
+
session_id=session_id,
|
|
401
|
+
project_service=project_service,
|
|
402
|
+
component=component,
|
|
403
|
+
log_prefix=log_prefix,
|
|
404
|
+
inject_full_context=should_inject_full_context,
|
|
405
|
+
)
|
|
406
|
+
|
|
407
|
+
# Update the message with project context if it was modified
|
|
408
|
+
if modified_message_text != message_text:
|
|
409
|
+
# Create new text part with project context
|
|
410
|
+
new_text_part = a2a.create_text_part(modified_message_text)
|
|
411
|
+
|
|
412
|
+
# Get existing parts and replace the first text part with the modified one
|
|
413
|
+
existing_parts = a2a.get_parts_from_message(payload.params.message)
|
|
414
|
+
new_parts = []
|
|
415
|
+
text_part_replaced = False
|
|
416
|
+
|
|
417
|
+
for part in existing_parts:
|
|
418
|
+
if hasattr(part, "text") and not text_part_replaced:
|
|
419
|
+
new_parts.append(new_text_part)
|
|
420
|
+
text_part_replaced = True
|
|
421
|
+
else:
|
|
422
|
+
new_parts.append(part)
|
|
423
|
+
|
|
424
|
+
# If no text part was found, add the new text part at the beginning
|
|
425
|
+
if not text_part_replaced:
|
|
426
|
+
new_parts.insert(0, new_text_part)
|
|
427
|
+
|
|
428
|
+
# Update the message with the new parts
|
|
429
|
+
modified_message = a2a.update_message_parts(payload.params.message, new_parts)
|
|
430
|
+
|
|
431
|
+
# Use the helper to get the unwrapped parts from the modified message (with project context if applied).
|
|
432
|
+
a2a_parts = a2a.get_parts_from_message(modified_message)
|
|
145
433
|
|
|
146
434
|
external_req_ctx = {
|
|
147
435
|
"app_name_for_artifacts": component.gateway_id,
|
|
@@ -341,6 +629,7 @@ async def send_task_to_agent(
|
|
|
341
629
|
payload: SendMessageRequest,
|
|
342
630
|
session_manager: SessionManager = Depends(get_session_manager),
|
|
343
631
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
632
|
+
project_service: ProjectService | None = Depends(get_project_service_optional),
|
|
344
633
|
):
|
|
345
634
|
"""
|
|
346
635
|
Submits a non-streaming task request to the specified agent.
|
|
@@ -351,6 +640,7 @@ async def send_task_to_agent(
|
|
|
351
640
|
payload=payload,
|
|
352
641
|
session_manager=session_manager,
|
|
353
642
|
component=component,
|
|
643
|
+
project_service=project_service,
|
|
354
644
|
is_streaming=False,
|
|
355
645
|
session_service=None,
|
|
356
646
|
)
|
|
@@ -362,6 +652,7 @@ async def subscribe_task_from_agent(
|
|
|
362
652
|
payload: SendStreamingMessageRequest,
|
|
363
653
|
session_manager: SessionManager = Depends(get_session_manager),
|
|
364
654
|
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
655
|
+
project_service: ProjectService | None = Depends(get_project_service_optional),
|
|
365
656
|
session_service: SessionService = Depends(get_session_business_service),
|
|
366
657
|
):
|
|
367
658
|
"""
|
|
@@ -374,6 +665,7 @@ async def subscribe_task_from_agent(
|
|
|
374
665
|
payload=payload,
|
|
375
666
|
session_manager=session_manager,
|
|
376
667
|
component=component,
|
|
668
|
+
project_service=project_service,
|
|
377
669
|
is_streaming=True,
|
|
378
670
|
session_service=session_service,
|
|
379
671
|
)
|