solace-agent-mesh 1.3.1__py3-none-any.whl → 1.3.3__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/artifacts/filesystem_artifact_service.py +16 -8
- solace_agent_mesh/agent/protocol/event_handlers.py +91 -0
- solace_agent_mesh/agent/sac/app.py +2 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/0e682baa.da822665.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.43771adc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.3f34bf76.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/483cef9a.8d318c2f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.dff11eca.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/75384d09.abdf9cf9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.abf2be91.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.5a319fd4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.1d029b81.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{aba87c2f.071e2d94.js → aba87c2f.4ddf32f2.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.abca774a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae4415af.24cdc514.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/bac0be12.27ee2c26.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{cee5d587.f5b73ca1.js → cee5d587.f1e1ca86.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.cad4dbf2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f897a61a.bc634a3e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{main.1c79039d.js → main.e82b32e6.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.aad1f874.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +18 -18
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +23 -23
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +8 -8
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +18 -18
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +8 -8
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/lunr-index-1757873594308.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757873594308.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{main-C1k9E0aC.js → main-DjoMeldu.js} +8 -8
- solace_agent_mesh/client/webui/frontend/static/index.html +1 -1
- solace_agent_mesh/common/a2a/__init__.py +4 -0
- solace_agent_mesh/common/a2a/protocol.py +20 -0
- solace_agent_mesh/common/sac/sam_component_base.py +29 -9
- solace_agent_mesh/common/sam_events/__init__.py +9 -0
- solace_agent_mesh/common/sam_events/event_service.py +207 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +1 -1
- solace_agent_mesh/gateway/http_sse/component.py +45 -35
- solace_agent_mesh/gateway/http_sse/dependencies.py +123 -60
- solace_agent_mesh/gateway/http_sse/main.py +20 -33
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/message.py +41 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +45 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +16 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +64 -0
- solace_agent_mesh/gateway/http_sse/repository/message_repository.py +78 -0
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/repository/models/base.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +27 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +27 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +139 -0
- solace_agent_mesh/gateway/http_sse/routers/config.py +1 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +20 -0
- solace_agent_mesh/gateway/http_sse/{api → routers}/dto/requests/session_requests.py +1 -8
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +16 -0
- solace_agent_mesh/gateway/http_sse/{api → routers}/dto/responses/session_responses.py +3 -30
- solace_agent_mesh/gateway/http_sse/{api/controllers/session_controller.py → routers/sessions.py} +20 -77
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +42 -49
- solace_agent_mesh/gateway/http_sse/{api/controllers/user_controller.py → routers/users.py} +1 -1
- solace_agent_mesh/gateway/http_sse/services/session_service.py +245 -0
- solace_agent_mesh/gateway/http_sse/session_manager.py +0 -3
- solace_agent_mesh/gateway/http_sse/shared/enums.py +0 -5
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/RECORD +120 -128
- solace_agent_mesh/assets/docs/assets/js/0e682baa.b3bbde9a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1023fc19.364235d5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.1b0ec6f9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.a8c5ce5a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.8909df92.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/332e10b5.7a103f42.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3d406171.0b9eeed1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/442a8107.b3159bb2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4e972867.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.0d080cd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/768e31b0.8b51cd70.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/945fb41e.c63791d1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.472b0310.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.4b7fa6a2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae4415af.7a2f0bbf.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/bac0be12.f50d9bac.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c2c06897.587b4af5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cc969b05.bd3e0d6c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.b6535013.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f897a61a.0aa29dbb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/runtime~main.858117b7.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1757531604543.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1757531604543.json +0 -1
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +0 -676
- solace_agent_mesh/gateway/http_sse/api/__init__.py +0 -11
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +0 -9
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +0 -279
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +0 -37
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +0 -66
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +0 -43
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +0 -74
- solace_agent_mesh/gateway/http_sse/application/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +0 -135
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +0 -90
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +0 -54
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +0 -4
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +0 -123
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +0 -4
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +0 -16
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +0 -119
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +0 -31
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +0 -12
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +0 -174
- /solace_agent_mesh/assets/docs/assets/js/{main.1c79039d.js.LICENSE.txt → main.e82b32e6.js.LICENSE.txt} +0 -0
- /solace_agent_mesh/gateway/http_sse/{api → routers}/dto/__init__.py +0 -0
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,279 +0,0 @@
|
|
|
1
|
-
from typing import TYPE_CHECKING
|
|
2
|
-
|
|
3
|
-
from fastapi import APIRouter, Depends, File, Form, HTTPException
|
|
4
|
-
from fastapi import Request as FastAPIRequest
|
|
5
|
-
from fastapi import UploadFile, status
|
|
6
|
-
from solace_ai_connector.common.log import log
|
|
7
|
-
|
|
8
|
-
from a2a.types import InternalError, InvalidRequestError, JSONRPCResponse
|
|
9
|
-
from .....common import a2a
|
|
10
|
-
from ...dependencies import (
|
|
11
|
-
get_sac_component,
|
|
12
|
-
get_session_manager,
|
|
13
|
-
get_user_id,
|
|
14
|
-
)
|
|
15
|
-
from ...session_manager import SessionManager
|
|
16
|
-
from ...shared.enums import SenderType
|
|
17
|
-
from ..dto.requests.task_requests import (
|
|
18
|
-
CancelTaskRequest,
|
|
19
|
-
ProcessedTaskRequest,
|
|
20
|
-
TaskFilesInfo,
|
|
21
|
-
)
|
|
22
|
-
|
|
23
|
-
if TYPE_CHECKING:
|
|
24
|
-
from ...component import WebUIBackendComponent
|
|
25
|
-
|
|
26
|
-
router = APIRouter()
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
@router.post("/send", response_model=JSONRPCResponse)
|
|
30
|
-
async def send_task_to_agent(
|
|
31
|
-
request: FastAPIRequest,
|
|
32
|
-
agent_name: str = Form(...),
|
|
33
|
-
message: str = Form(...),
|
|
34
|
-
files: list[UploadFile] = File([]),
|
|
35
|
-
session_manager: SessionManager = Depends(get_session_manager),
|
|
36
|
-
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
37
|
-
user_id: str = Depends(get_user_id),
|
|
38
|
-
):
|
|
39
|
-
"""
|
|
40
|
-
Submits a non-streaming task request to the specified agent.
|
|
41
|
-
This corresponds to the A2A `tasks/send` method.
|
|
42
|
-
"""
|
|
43
|
-
log_prefix = "[POST /api/v1/tasks/send] "
|
|
44
|
-
log.info("%sReceived request for agent: %s", log_prefix, agent_name)
|
|
45
|
-
|
|
46
|
-
try:
|
|
47
|
-
task_files = []
|
|
48
|
-
for file in files:
|
|
49
|
-
if file.filename:
|
|
50
|
-
task_files.append(
|
|
51
|
-
TaskFilesInfo(
|
|
52
|
-
filename=file.filename,
|
|
53
|
-
content_type=file.content_type or "application/octet-stream",
|
|
54
|
-
size=0, # We'd need to read the file to get size
|
|
55
|
-
)
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
request_dto = ProcessedTaskRequest(
|
|
59
|
-
agent_name=agent_name, message=message, user_id=user_id, files=task_files
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
# Continue with existing logic
|
|
63
|
-
client_id = session_manager.get_a2a_client_id(request)
|
|
64
|
-
session_id = session_manager.ensure_a2a_session(request)
|
|
65
|
-
|
|
66
|
-
log.info(
|
|
67
|
-
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
68
|
-
)
|
|
69
|
-
|
|
70
|
-
external_event_data = {
|
|
71
|
-
"agent_name": agent_name,
|
|
72
|
-
"message": message,
|
|
73
|
-
"files": files,
|
|
74
|
-
"client_id": client_id,
|
|
75
|
-
"a2a_session_id": session_id,
|
|
76
|
-
}
|
|
77
|
-
(
|
|
78
|
-
target_agent,
|
|
79
|
-
a2a_parts,
|
|
80
|
-
external_request_context,
|
|
81
|
-
) = await component._translate_external_input(external_event_data)
|
|
82
|
-
|
|
83
|
-
user_identity = {"id": user_id}
|
|
84
|
-
log.info(
|
|
85
|
-
"%sAuthenticated user identity: %s",
|
|
86
|
-
log_prefix,
|
|
87
|
-
user_identity.get("id", "unknown"),
|
|
88
|
-
)
|
|
89
|
-
task_id = await component.submit_a2a_task(
|
|
90
|
-
target_agent_name=target_agent,
|
|
91
|
-
a2a_parts=a2a_parts,
|
|
92
|
-
user_identity=user_identity,
|
|
93
|
-
external_request_context=external_request_context,
|
|
94
|
-
is_streaming=False,
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
log.info(
|
|
98
|
-
"%sNon-streaming task submitted successfully. TaskID: %s",
|
|
99
|
-
log_prefix,
|
|
100
|
-
task_id,
|
|
101
|
-
)
|
|
102
|
-
|
|
103
|
-
return JSONRPCResponse(result={"taskId": task_id})
|
|
104
|
-
|
|
105
|
-
except InvalidRequestError as e:
|
|
106
|
-
log.warning("%sInvalid request: %s", log_prefix, e.message, exc_info=True)
|
|
107
|
-
raise HTTPException(
|
|
108
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
109
|
-
detail=e.model_dump(exclude_none=True),
|
|
110
|
-
)
|
|
111
|
-
except Exception as e:
|
|
112
|
-
log.exception("%sUnexpected error processing task: %s", log_prefix, e)
|
|
113
|
-
error_resp = a2a.create_internal_error(message=f"Failed to process task: {e}")
|
|
114
|
-
raise HTTPException(
|
|
115
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
116
|
-
detail=error_resp.model_dump(exclude_none=True),
|
|
117
|
-
)
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
@router.post("/subscribe", response_model=JSONRPCResponse)
|
|
121
|
-
async def subscribe_task_from_agent(
|
|
122
|
-
request: FastAPIRequest,
|
|
123
|
-
agent_name: str = Form(...),
|
|
124
|
-
message: str = Form(...),
|
|
125
|
-
files: list[UploadFile] = File([]),
|
|
126
|
-
session_id: str | None = Form(None),
|
|
127
|
-
session_manager: SessionManager = Depends(get_session_manager),
|
|
128
|
-
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
129
|
-
user_id: str = Depends(get_user_id),
|
|
130
|
-
):
|
|
131
|
-
"""
|
|
132
|
-
Submits a streaming task request (`tasks/sendSubscribe`) to the specified agent.
|
|
133
|
-
"""
|
|
134
|
-
log_prefix = "[POST /api/v1/tasks/subscribe] "
|
|
135
|
-
log.info("%sReceived streaming request for agent: %s", log_prefix, agent_name)
|
|
136
|
-
|
|
137
|
-
try:
|
|
138
|
-
task_files = []
|
|
139
|
-
for file in files:
|
|
140
|
-
if file.filename:
|
|
141
|
-
task_files.append(
|
|
142
|
-
TaskFilesInfo(
|
|
143
|
-
filename=file.filename,
|
|
144
|
-
content_type=file.content_type or "application/octet-stream",
|
|
145
|
-
size=0,
|
|
146
|
-
)
|
|
147
|
-
)
|
|
148
|
-
|
|
149
|
-
request_dto = ProcessedTaskRequest(
|
|
150
|
-
agent_name=agent_name,
|
|
151
|
-
message=message,
|
|
152
|
-
user_id=user_id,
|
|
153
|
-
session_id=session_id,
|
|
154
|
-
files=task_files,
|
|
155
|
-
)
|
|
156
|
-
|
|
157
|
-
client_id = session_manager.get_a2a_client_id(request)
|
|
158
|
-
|
|
159
|
-
# If session_id is not provided by the client, create a new one.
|
|
160
|
-
if not session_id:
|
|
161
|
-
log.info("%sNo session_id provided, creating a new one.", log_prefix)
|
|
162
|
-
session_id = session_manager.start_new_a2a_session(request)
|
|
163
|
-
|
|
164
|
-
# Store message only if persistence is available
|
|
165
|
-
if hasattr(component, "persistence_service") and component.persistence_service:
|
|
166
|
-
try:
|
|
167
|
-
from ...dependencies import get_session_service
|
|
168
|
-
session_service = get_session_service(component)
|
|
169
|
-
message_domain = session_service.add_message_to_session(
|
|
170
|
-
session_id=session_id,
|
|
171
|
-
user_id=user_id,
|
|
172
|
-
message=message,
|
|
173
|
-
sender_type=SenderType.USER,
|
|
174
|
-
sender_name=user_id,
|
|
175
|
-
agent_id=agent_name,
|
|
176
|
-
)
|
|
177
|
-
# Use the actual session ID from the message (may be different if session was recreated)
|
|
178
|
-
if message_domain:
|
|
179
|
-
session_id = message_domain.session_id
|
|
180
|
-
except ValueError as e:
|
|
181
|
-
# Handle business domain validation errors
|
|
182
|
-
log.warning("Validation error in session service: %s", e)
|
|
183
|
-
raise HTTPException(
|
|
184
|
-
status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
|
|
185
|
-
)
|
|
186
|
-
except Exception as e:
|
|
187
|
-
log.error("Failed to store message in session service: %s", e)
|
|
188
|
-
raise HTTPException(
|
|
189
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
190
|
-
detail="Failed to store message",
|
|
191
|
-
)
|
|
192
|
-
else:
|
|
193
|
-
log.debug("%sNo persistence available - skipping message storage", log_prefix)
|
|
194
|
-
|
|
195
|
-
log.info(
|
|
196
|
-
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
197
|
-
)
|
|
198
|
-
|
|
199
|
-
external_event_data = {
|
|
200
|
-
"agent_name": agent_name,
|
|
201
|
-
"message": message,
|
|
202
|
-
"files": files,
|
|
203
|
-
"client_id": client_id,
|
|
204
|
-
"a2a_session_id": session_id,
|
|
205
|
-
}
|
|
206
|
-
(
|
|
207
|
-
target_agent,
|
|
208
|
-
a2a_parts,
|
|
209
|
-
external_request_context,
|
|
210
|
-
) = await component._translate_external_input(external_event_data)
|
|
211
|
-
|
|
212
|
-
user_identity = {"id": user_id}
|
|
213
|
-
log.info(
|
|
214
|
-
"%sAuthenticated user identity: %s",
|
|
215
|
-
log_prefix,
|
|
216
|
-
user_identity.get("id", "unknown"),
|
|
217
|
-
)
|
|
218
|
-
task_id = await component.submit_a2a_task(
|
|
219
|
-
target_agent_name=target_agent,
|
|
220
|
-
a2a_parts=a2a_parts,
|
|
221
|
-
user_identity=user_identity,
|
|
222
|
-
external_request_context=external_request_context,
|
|
223
|
-
is_streaming=True,
|
|
224
|
-
)
|
|
225
|
-
|
|
226
|
-
log.info(
|
|
227
|
-
"%sStreaming task submitted successfully. TaskID: %s", log_prefix, task_id
|
|
228
|
-
)
|
|
229
|
-
|
|
230
|
-
return JSONRPCResponse(result={"taskId": task_id, "sessionId": session_id})
|
|
231
|
-
|
|
232
|
-
except InvalidRequestError as e:
|
|
233
|
-
log.warning("%sInvalid request: %s", log_prefix, e.message, exc_info=True)
|
|
234
|
-
raise HTTPException(
|
|
235
|
-
status_code=status.HTTP_400_BAD_REQUEST,
|
|
236
|
-
detail=e.model_dump(exclude_none=True),
|
|
237
|
-
)
|
|
238
|
-
except HTTPException:
|
|
239
|
-
# Re-raise HTTPExceptions (like 422 validation errors) without modification
|
|
240
|
-
raise
|
|
241
|
-
except Exception as e:
|
|
242
|
-
log.exception("%sUnexpected error processing task: %s", log_prefix, e)
|
|
243
|
-
error_resp = a2a.create_internal_error(message=f"Failed to process task: {e}")
|
|
244
|
-
raise HTTPException(
|
|
245
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
246
|
-
detail=error_resp.model_dump(exclude_none=True),
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
@router.post("/cancel", response_model=JSONRPCResponse)
|
|
251
|
-
async def cancel_agent_task(
|
|
252
|
-
request: FastAPIRequest,
|
|
253
|
-
task_id: str = Form(...),
|
|
254
|
-
session_manager: SessionManager = Depends(get_session_manager),
|
|
255
|
-
component: "WebUIBackendComponent" = Depends(get_sac_component),
|
|
256
|
-
user_id: str = Depends(get_user_id),
|
|
257
|
-
):
|
|
258
|
-
"""
|
|
259
|
-
Sends a cancellation request for a specific task.
|
|
260
|
-
"""
|
|
261
|
-
log_prefix = f"[POST /api/v1/tasks/cancel] TaskID: {task_id} "
|
|
262
|
-
log.info("%sReceived cancellation request.", log_prefix)
|
|
263
|
-
|
|
264
|
-
try:
|
|
265
|
-
request_dto = CancelTaskRequest(task_id=task_id, user_id=user_id)
|
|
266
|
-
|
|
267
|
-
client_id = session_manager.get_a2a_client_id(request)
|
|
268
|
-
await component.cancel_a2a_task(task_id, client_id)
|
|
269
|
-
log.info("%sCancellation request sent successfully.", log_prefix)
|
|
270
|
-
return JSONRPCResponse(
|
|
271
|
-
result={"message": f"Cancellation request sent for task {task_id}"}
|
|
272
|
-
)
|
|
273
|
-
except Exception as e:
|
|
274
|
-
log.exception("%sUnexpected error sending cancellation: %s", log_prefix, e)
|
|
275
|
-
error_resp = a2a.create_internal_error(message="Unexpected server error: %s" % e)
|
|
276
|
-
raise HTTPException(
|
|
277
|
-
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
278
|
-
detail=error_resp.model_dump(exclude_none=True),
|
|
279
|
-
)
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Request DTOs for API endpoints.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from .session_requests import (
|
|
6
|
-
GetSessionsRequest,
|
|
7
|
-
GetSessionRequest,
|
|
8
|
-
GetSessionHistoryRequest,
|
|
9
|
-
UpdateSessionRequest,
|
|
10
|
-
DeleteSessionRequest,
|
|
11
|
-
CreateSessionRequest,
|
|
12
|
-
)
|
|
13
|
-
from .task_requests import (
|
|
14
|
-
SendTaskRequest,
|
|
15
|
-
SubscribeTaskRequest,
|
|
16
|
-
CancelTaskRequest,
|
|
17
|
-
GetTaskStatusRequest,
|
|
18
|
-
TaskFilesInfo,
|
|
19
|
-
ProcessedTaskRequest,
|
|
20
|
-
)
|
|
21
|
-
|
|
22
|
-
__all__ = [
|
|
23
|
-
# Session requests
|
|
24
|
-
"GetSessionsRequest",
|
|
25
|
-
"GetSessionRequest",
|
|
26
|
-
"GetSessionHistoryRequest",
|
|
27
|
-
"UpdateSessionRequest",
|
|
28
|
-
"DeleteSessionRequest",
|
|
29
|
-
"CreateSessionRequest",
|
|
30
|
-
# Task requests
|
|
31
|
-
"SendTaskRequest",
|
|
32
|
-
"SubscribeTaskRequest",
|
|
33
|
-
"CancelTaskRequest",
|
|
34
|
-
"GetTaskStatusRequest",
|
|
35
|
-
"TaskFilesInfo",
|
|
36
|
-
"ProcessedTaskRequest",
|
|
37
|
-
]
|
|
@@ -1,66 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Task-related request DTOs.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from typing import List, Optional, Dict, Any
|
|
6
|
-
from pydantic import BaseModel, Field
|
|
7
|
-
from fastapi import UploadFile
|
|
8
|
-
|
|
9
|
-
from ....shared.types import TaskId, UserId, SessionId, AgentId
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class SendTaskRequest(BaseModel):
|
|
13
|
-
"""Request DTO for sending a non-streaming task."""
|
|
14
|
-
agent_name: str = Field(..., description="The name of the target A2A agent")
|
|
15
|
-
message: str = Field(..., description="The user's message or prompt")
|
|
16
|
-
user_id: UserId
|
|
17
|
-
client_id: Optional[str] = None
|
|
18
|
-
session_id: Optional[SessionId] = None
|
|
19
|
-
|
|
20
|
-
class Config:
|
|
21
|
-
# UploadFile cannot be included in Pydantic models directly
|
|
22
|
-
# Files will be handled separately in the controller
|
|
23
|
-
arbitrary_types_allowed = True
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
class SubscribeTaskRequest(BaseModel):
|
|
27
|
-
"""Request DTO for sending a streaming task."""
|
|
28
|
-
agent_name: str = Field(..., description="The name of the target A2A agent")
|
|
29
|
-
message: str = Field(..., description="The user's message or prompt")
|
|
30
|
-
user_id: UserId
|
|
31
|
-
session_id: Optional[SessionId] = None
|
|
32
|
-
client_id: Optional[str] = None
|
|
33
|
-
|
|
34
|
-
class Config:
|
|
35
|
-
arbitrary_types_allowed = True
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
class CancelTaskRequest(BaseModel):
|
|
39
|
-
"""Request DTO for cancelling a task."""
|
|
40
|
-
task_id: TaskId = Field(..., description="The ID of the task to cancel")
|
|
41
|
-
client_id: Optional[str] = None
|
|
42
|
-
user_id: UserId
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class GetTaskStatusRequest(BaseModel):
|
|
46
|
-
"""Request DTO for getting task status."""
|
|
47
|
-
task_id: TaskId
|
|
48
|
-
user_id: UserId
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
class TaskFilesInfo(BaseModel):
|
|
52
|
-
"""Information about uploaded files for a task."""
|
|
53
|
-
filename: str
|
|
54
|
-
content_type: str
|
|
55
|
-
size: int
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
class ProcessedTaskRequest(BaseModel):
|
|
59
|
-
"""Internal DTO for processed task request with file information."""
|
|
60
|
-
agent_name: str
|
|
61
|
-
message: str
|
|
62
|
-
user_id: UserId
|
|
63
|
-
session_id: Optional[SessionId] = None
|
|
64
|
-
client_id: Optional[str] = None
|
|
65
|
-
files: List[TaskFilesInfo] = []
|
|
66
|
-
metadata: Optional[Dict[str, Any]] = None
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Response DTOs for API endpoints.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from .session_responses import (
|
|
6
|
-
MessageResponse,
|
|
7
|
-
SessionResponse,
|
|
8
|
-
SessionListResponse,
|
|
9
|
-
SessionHistoryResponse,
|
|
10
|
-
SessionCreatedResponse,
|
|
11
|
-
SessionUpdatedResponse,
|
|
12
|
-
SessionDeletedResponse,
|
|
13
|
-
)
|
|
14
|
-
from .task_responses import (
|
|
15
|
-
TaskResponse,
|
|
16
|
-
SendTaskResponse,
|
|
17
|
-
SubscribeTaskResponse,
|
|
18
|
-
CancelTaskResponse,
|
|
19
|
-
TaskStatusResponse,
|
|
20
|
-
TaskListResponse,
|
|
21
|
-
TaskErrorResponse,
|
|
22
|
-
JSONRPCTaskResponse,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
__all__ = [
|
|
26
|
-
# Session responses
|
|
27
|
-
"MessageResponse",
|
|
28
|
-
"SessionResponse",
|
|
29
|
-
"SessionListResponse",
|
|
30
|
-
"SessionHistoryResponse",
|
|
31
|
-
"SessionCreatedResponse",
|
|
32
|
-
"SessionUpdatedResponse",
|
|
33
|
-
"SessionDeletedResponse",
|
|
34
|
-
# Task responses
|
|
35
|
-
"TaskResponse",
|
|
36
|
-
"SendTaskResponse",
|
|
37
|
-
"SubscribeTaskResponse",
|
|
38
|
-
"CancelTaskResponse",
|
|
39
|
-
"TaskStatusResponse",
|
|
40
|
-
"TaskListResponse",
|
|
41
|
-
"TaskErrorResponse",
|
|
42
|
-
"JSONRPCTaskResponse",
|
|
43
|
-
]
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Task-related response DTOs.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
from typing import Optional, Dict, Any, List
|
|
6
|
-
from datetime import datetime
|
|
7
|
-
from pydantic import BaseModel, Field
|
|
8
|
-
|
|
9
|
-
from ....shared.types import TaskId, UserId, SessionId, AgentId
|
|
10
|
-
from ....shared.enums import TaskStatus
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class TaskResponse(BaseModel):
|
|
14
|
-
"""Response DTO for task information."""
|
|
15
|
-
task_id: TaskId
|
|
16
|
-
agent_name: str
|
|
17
|
-
status: TaskStatus
|
|
18
|
-
user_id: UserId
|
|
19
|
-
session_id: Optional[SessionId] = None
|
|
20
|
-
created_at: datetime
|
|
21
|
-
updated_at: Optional[datetime] = None
|
|
22
|
-
completed_at: Optional[datetime] = None
|
|
23
|
-
error_message: Optional[str] = None
|
|
24
|
-
metadata: Optional[Dict[str, Any]] = None
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
class SendTaskResponse(BaseModel):
|
|
28
|
-
"""Response DTO for send task endpoint."""
|
|
29
|
-
task_id: TaskId
|
|
30
|
-
message: str = "Task submitted successfully"
|
|
31
|
-
status: TaskStatus = TaskStatus.PENDING
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
class SubscribeTaskResponse(BaseModel):
|
|
35
|
-
"""Response DTO for subscribe task endpoint."""
|
|
36
|
-
task_id: TaskId
|
|
37
|
-
session_id: SessionId
|
|
38
|
-
message: str = "Streaming task submitted successfully"
|
|
39
|
-
status: TaskStatus = TaskStatus.PENDING
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
class CancelTaskResponse(BaseModel):
|
|
43
|
-
"""Response DTO for cancel task endpoint."""
|
|
44
|
-
task_id: TaskId
|
|
45
|
-
message: str = "Cancellation request sent successfully"
|
|
46
|
-
cancelled_at: datetime
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
class TaskStatusResponse(BaseModel):
|
|
50
|
-
"""Response DTO for task status."""
|
|
51
|
-
task: TaskResponse
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
class TaskListResponse(BaseModel):
|
|
55
|
-
"""Response DTO for listing tasks."""
|
|
56
|
-
tasks: List[TaskResponse]
|
|
57
|
-
total_count: int
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
class TaskErrorResponse(BaseModel):
|
|
61
|
-
"""Response DTO for task errors."""
|
|
62
|
-
task_id: TaskId
|
|
63
|
-
error_type: str
|
|
64
|
-
error_message: str
|
|
65
|
-
error_details: Optional[Dict[str, Any]] = None
|
|
66
|
-
occurred_at: datetime
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
class JSONRPCTaskResponse(BaseModel):
|
|
70
|
-
"""Response DTO matching the existing JSONRPC format."""
|
|
71
|
-
result: Dict[str, Any]
|
|
72
|
-
error: Optional[Dict[str, Any]] = None
|
|
73
|
-
id: Optional[str] = None
|
|
74
|
-
jsonrpc: str = "2.0"
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import uuid
|
|
2
|
-
from datetime import datetime, timezone
|
|
3
|
-
|
|
4
|
-
from solace_ai_connector.common.log import log
|
|
5
|
-
|
|
6
|
-
from ...domain.entities.session import Message, Session, SessionHistory
|
|
7
|
-
from ...domain.repositories.session_repository import (
|
|
8
|
-
IMessageRepository,
|
|
9
|
-
ISessionRepository,
|
|
10
|
-
)
|
|
11
|
-
from ...shared.enums import MessageType, SenderType, SessionStatus
|
|
12
|
-
from ...shared.types import PaginationInfo, SessionId, UserId
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class SessionService:
|
|
16
|
-
def __init__(
|
|
17
|
-
self,
|
|
18
|
-
session_repository: ISessionRepository,
|
|
19
|
-
message_repository: IMessageRepository,
|
|
20
|
-
):
|
|
21
|
-
self.session_repository = session_repository
|
|
22
|
-
self.message_repository = message_repository
|
|
23
|
-
|
|
24
|
-
def get_user_sessions(
|
|
25
|
-
self, user_id: UserId, pagination: PaginationInfo | None = None
|
|
26
|
-
) -> list[Session]:
|
|
27
|
-
return self.session_repository.get_by_user_id(user_id, pagination)
|
|
28
|
-
|
|
29
|
-
def get_session(self, session_id: SessionId, user_id: UserId) -> Session | None:
|
|
30
|
-
return self.session_repository.get_user_session(session_id, user_id)
|
|
31
|
-
|
|
32
|
-
def get_session_history(
|
|
33
|
-
self,
|
|
34
|
-
session_id: SessionId,
|
|
35
|
-
user_id: UserId,
|
|
36
|
-
pagination: PaginationInfo | None = None,
|
|
37
|
-
) -> SessionHistory | None:
|
|
38
|
-
session = self.session_repository.get_user_session(session_id, user_id)
|
|
39
|
-
if not session:
|
|
40
|
-
return None
|
|
41
|
-
|
|
42
|
-
messages = self.message_repository.get_by_session_id(session_id, pagination)
|
|
43
|
-
|
|
44
|
-
return SessionHistory(
|
|
45
|
-
session=session,
|
|
46
|
-
messages=messages,
|
|
47
|
-
total_message_count=len(messages),
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
def create_session(
|
|
51
|
-
self,
|
|
52
|
-
user_id: UserId,
|
|
53
|
-
name: str | None = None,
|
|
54
|
-
agent_id: str | None = None,
|
|
55
|
-
session_id: str | None = None,
|
|
56
|
-
) -> Session:
|
|
57
|
-
if not user_id or user_id.strip() == "":
|
|
58
|
-
raise ValueError(f"user_id cannot be None or empty. Received: {user_id}")
|
|
59
|
-
|
|
60
|
-
if not session_id:
|
|
61
|
-
session_id = str(uuid.uuid4())
|
|
62
|
-
|
|
63
|
-
now = datetime.now(timezone.utc)
|
|
64
|
-
session = Session(
|
|
65
|
-
id=session_id,
|
|
66
|
-
user_id=user_id,
|
|
67
|
-
name=name,
|
|
68
|
-
agent_id=agent_id,
|
|
69
|
-
status=SessionStatus.ACTIVE,
|
|
70
|
-
created_at=now,
|
|
71
|
-
updated_at=now,
|
|
72
|
-
last_activity=now,
|
|
73
|
-
)
|
|
74
|
-
|
|
75
|
-
return self.session_repository.create(session)
|
|
76
|
-
|
|
77
|
-
def update_session_name(
|
|
78
|
-
self, session_id: SessionId, user_id: UserId, name: str
|
|
79
|
-
) -> Session | None:
|
|
80
|
-
session = self.session_repository.get_user_session(session_id, user_id)
|
|
81
|
-
if not session:
|
|
82
|
-
return None
|
|
83
|
-
|
|
84
|
-
session.update_name(name)
|
|
85
|
-
return self.session_repository.update(session)
|
|
86
|
-
|
|
87
|
-
def delete_session(self, session_id: SessionId, user_id: UserId) -> bool:
|
|
88
|
-
session = self.session_repository.get_user_session(session_id, user_id)
|
|
89
|
-
if not session:
|
|
90
|
-
return False
|
|
91
|
-
|
|
92
|
-
if not session.can_be_deleted_by_user(user_id):
|
|
93
|
-
return False
|
|
94
|
-
|
|
95
|
-
self.message_repository.delete_by_session_id(session_id)
|
|
96
|
-
return self.session_repository.delete(session_id, user_id)
|
|
97
|
-
|
|
98
|
-
def add_message_to_session(
|
|
99
|
-
self,
|
|
100
|
-
session_id: SessionId,
|
|
101
|
-
user_id: UserId,
|
|
102
|
-
message: str,
|
|
103
|
-
sender_type: SenderType,
|
|
104
|
-
sender_name: str,
|
|
105
|
-
agent_id: str | None = None,
|
|
106
|
-
) -> Message | None:
|
|
107
|
-
if not user_id or user_id.strip() == "":
|
|
108
|
-
raise ValueError(f"user_id cannot be None or empty. Received: {user_id}")
|
|
109
|
-
|
|
110
|
-
session = self.session_repository.get_user_session(session_id, user_id)
|
|
111
|
-
if not session:
|
|
112
|
-
log.error(f"Session {session_id} not found for user {user_id}")
|
|
113
|
-
return None
|
|
114
|
-
|
|
115
|
-
if agent_id and not session.agent_id:
|
|
116
|
-
session.agent_id = agent_id
|
|
117
|
-
self.session_repository.update(session)
|
|
118
|
-
log.info(f"Updated session {session_id} with agent_id: {agent_id}")
|
|
119
|
-
|
|
120
|
-
message_entity = Message(
|
|
121
|
-
id=str(uuid.uuid4()),
|
|
122
|
-
session_id=session_id,
|
|
123
|
-
message=message,
|
|
124
|
-
sender_type=sender_type,
|
|
125
|
-
sender_name=sender_name,
|
|
126
|
-
message_type=MessageType.TEXT,
|
|
127
|
-
created_at=datetime.now(timezone.utc),
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
message_entity.validate_message_content()
|
|
131
|
-
|
|
132
|
-
session.mark_activity()
|
|
133
|
-
self.session_repository.update(session)
|
|
134
|
-
|
|
135
|
-
return self.message_repository.create(message_entity)
|