solace-agent-mesh 1.4.12__py3-none-any.whl → 1.5.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 +3 -4
- solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
- solace_agent_mesh/agent/adk/callbacks.py +51 -2
- solace_agent_mesh/agent/adk/models/lite_llm.py +1 -0
- solace_agent_mesh/agent/adk/models/models_llm.txt +1 -2
- solace_agent_mesh/agent/agent_llm.txt +1 -1
- solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
- solace_agent_mesh/agent/protocol/event_handlers.py +2 -13
- solace_agent_mesh/agent/protocol/protocol_llm.txt +15 -2
- solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
- solace_agent_mesh/agent/sac/component.py +51 -21
- solace_agent_mesh/agent/sac/sac_llm.txt +15 -1
- solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
- solace_agent_mesh/agent/sac/task_execution_context.py +73 -0
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +148 -154
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +274 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +1 -1
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/483cef9a.bf9398af.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js → main.0c149855.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/{runtime~main.40527046.js → runtime~main.c66557e4.js} +1 -1
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +8 -4
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +3 -3
- 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 +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +3 -3
- 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 +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +3 -3
- 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 +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +3 -3
- 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 +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +3 -3
- 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 +3 -3
- solace_agent_mesh/assets/docs/lunr-index-1760032255022.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1760032255022.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/{authCallback-j1LW-wlq.js → authCallback-DwrxZE0E.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-B9p_nFNA.js → client-DarGQzyw.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-CZbpmwfA.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C__uuUkB.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CS5YMf8a.js → vendor-BKIeiHj_.js} +80 -70
- 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 +1 -1
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +1 -1
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +23 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +93 -15
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +23 -0
- solace_agent_mesh/common/common_llm.txt +24 -39
- solace_agent_mesh/common/common_llm_detail.txt +2562 -0
- solace_agent_mesh/common/data_parts.py +9 -1
- solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
- solace_agent_mesh/common/sac/sac_llm.txt +1 -1
- solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
- solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
- solace_agent_mesh/common/services/services_llm.txt +57 -6
- solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
- solace_agent_mesh/common/utils/utils_llm.txt +75 -87
- solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
- solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
- solace_agent_mesh/gateway/base/app.py +1 -1
- solace_agent_mesh/gateway/base/base_llm.txt +1 -1
- solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
- solace_agent_mesh/gateway/gateway_llm.txt +242 -235
- solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +295 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +10 -1
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +155 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +1 -1
- solace_agent_mesh/gateway/http_sse/app.py +148 -2
- solace_agent_mesh/gateway/http_sse/component.py +368 -60
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +46 -6
- solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +108 -0
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +1 -1
- solace_agent_mesh/gateway/http_sse/dependencies.py +116 -26
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +172 -172
- solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
- solace_agent_mesh/gateway/http_sse/main.py +146 -41
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +3 -12
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +103 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +5 -3
- solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +263 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -16
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +81 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +73 -18
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -5
- solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
- solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +266 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +3 -3
- solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +32 -0
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +340 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +4 -53
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +173 -0
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/config.py +26 -4
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +346 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +3 -3
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +83 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +2 -10
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +5 -3
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +107 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +1 -15
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +37 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +255 -204
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +220 -40
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +168 -42
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +272 -0
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +241 -0
- solace_agent_mesh/gateway/http_sse/services/people_service.py +0 -80
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +177 -13
- solace_agent_mesh/gateway/http_sse/services/session_service.py +151 -84
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +317 -0
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +25 -14
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +285 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +7 -0
- solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
- solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +32 -0
- solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
- solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
- solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/RECORD +172 -124
- solace_agent_mesh/agent/adk/invocation_monitor.py +0 -295
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4736f2d8.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1759936913198.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1759936913198.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-ChRwcV89.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-DnnE01OM.js +0 -339
- solace_agent_mesh/gateway/http_sse/repository/entities/message.py +0 -41
- solace_agent_mesh/gateway/http_sse/repository/message_repository.py +0 -84
- solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +0 -45
- /solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js.LICENSE.txt → main.0c149855.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -5,11 +5,11 @@ Session repository implementation using SQLAlchemy.
|
|
|
5
5
|
from sqlalchemy.orm import Session as DBSession
|
|
6
6
|
|
|
7
7
|
from ..shared.base_repository import PaginatedRepository
|
|
8
|
+
from ..shared.pagination import PaginationParams
|
|
8
9
|
from ..shared.types import PaginationInfo, SessionId, UserId
|
|
9
|
-
from .entities import
|
|
10
|
+
from .entities import Session
|
|
10
11
|
from .interfaces import ISessionRepository
|
|
11
12
|
from .models import (
|
|
12
|
-
MessageModel,
|
|
13
13
|
SessionModel,
|
|
14
14
|
CreateSessionModel,
|
|
15
15
|
UpdateSessionModel,
|
|
@@ -29,14 +29,14 @@ class SessionRepository(PaginatedRepository[SessionModel, Session], ISessionRepo
|
|
|
29
29
|
return "session"
|
|
30
30
|
|
|
31
31
|
def find_by_user(
|
|
32
|
-
self, user_id: UserId, pagination:
|
|
32
|
+
self, user_id: UserId, pagination: PaginationParams | None = None
|
|
33
33
|
) -> list[Session]:
|
|
34
34
|
"""Find all sessions for a specific user."""
|
|
35
35
|
query = self.db.query(SessionModel).filter(SessionModel.user_id == user_id)
|
|
36
36
|
query = query.order_by(SessionModel.updated_time.desc())
|
|
37
37
|
|
|
38
38
|
if pagination:
|
|
39
|
-
offset = (pagination.
|
|
39
|
+
offset = (pagination.page_number - 1) * pagination.page_size
|
|
40
40
|
query = query.offset(offset).limit(pagination.page_size)
|
|
41
41
|
|
|
42
42
|
models = query.all()
|
|
@@ -96,52 +96,3 @@ class SessionRepository(PaginatedRepository[SessionModel, Session], ISessionRepo
|
|
|
96
96
|
# Use BaseRepository delete method
|
|
97
97
|
super().delete(self.db, session_id)
|
|
98
98
|
return True
|
|
99
|
-
|
|
100
|
-
def find_user_session_with_messages(
|
|
101
|
-
self,
|
|
102
|
-
session_id: SessionId,
|
|
103
|
-
user_id: UserId,
|
|
104
|
-
pagination: PaginationInfo | None = None,
|
|
105
|
-
) -> tuple[Session, list[Message]] | None:
|
|
106
|
-
"""Find a session with its messages."""
|
|
107
|
-
session_model = (
|
|
108
|
-
self.db.query(SessionModel)
|
|
109
|
-
.filter(
|
|
110
|
-
SessionModel.id == session_id,
|
|
111
|
-
SessionModel.user_id == user_id,
|
|
112
|
-
)
|
|
113
|
-
.first()
|
|
114
|
-
)
|
|
115
|
-
|
|
116
|
-
if not session_model:
|
|
117
|
-
return None
|
|
118
|
-
|
|
119
|
-
message_query = self.db.query(MessageModel).filter(
|
|
120
|
-
MessageModel.session_id == session_id
|
|
121
|
-
)
|
|
122
|
-
|
|
123
|
-
if pagination:
|
|
124
|
-
offset = (pagination.page - 1) * pagination.page_size
|
|
125
|
-
message_query = message_query.offset(offset).limit(pagination.page_size)
|
|
126
|
-
|
|
127
|
-
message_models = message_query.order_by(MessageModel.created_time.asc()).all()
|
|
128
|
-
|
|
129
|
-
session = Session.model_validate(session_model)
|
|
130
|
-
messages = [self._message_model_to_entity(model) for model in message_models]
|
|
131
|
-
|
|
132
|
-
return session, messages
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def _message_model_to_entity(self, model: MessageModel) -> Message:
|
|
136
|
-
"""Convert SQLAlchemy message model to domain entity."""
|
|
137
|
-
from ..shared.enums import MessageType, SenderType
|
|
138
|
-
|
|
139
|
-
return Message(
|
|
140
|
-
id=model.id,
|
|
141
|
-
session_id=model.session_id,
|
|
142
|
-
message=model.message,
|
|
143
|
-
sender_type=SenderType(model.sender_type),
|
|
144
|
-
sender_name=model.sender_name,
|
|
145
|
-
message_type=MessageType.TEXT, # Default for now
|
|
146
|
-
created_time=model.created_time,
|
|
147
|
-
)
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Task repository implementation using SQLAlchemy.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from sqlalchemy.orm import Session as DBSession
|
|
6
|
+
|
|
7
|
+
from ..shared.types import PaginationInfo, PaginationParams, UserId
|
|
8
|
+
from .entities import Task, TaskEvent
|
|
9
|
+
from .interfaces import ITaskRepository
|
|
10
|
+
from .models import TaskEventModel, TaskModel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class TaskRepository(ITaskRepository):
|
|
14
|
+
"""SQLAlchemy implementation of task repository."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, db: DBSession):
|
|
17
|
+
self.db = db
|
|
18
|
+
|
|
19
|
+
def save_task(self, task: Task) -> Task:
|
|
20
|
+
"""Create or update a task."""
|
|
21
|
+
model = self.db.query(TaskModel).filter(TaskModel.id == task.id).first()
|
|
22
|
+
|
|
23
|
+
if model:
|
|
24
|
+
# Update existing
|
|
25
|
+
model.end_time = task.end_time
|
|
26
|
+
model.status = task.status
|
|
27
|
+
model.total_input_tokens = task.total_input_tokens
|
|
28
|
+
model.total_output_tokens = task.total_output_tokens
|
|
29
|
+
model.total_cached_input_tokens = task.total_cached_input_tokens
|
|
30
|
+
model.token_usage_details = task.token_usage_details
|
|
31
|
+
else:
|
|
32
|
+
# Create new
|
|
33
|
+
model = TaskModel(
|
|
34
|
+
id=task.id,
|
|
35
|
+
user_id=task.user_id,
|
|
36
|
+
start_time=task.start_time,
|
|
37
|
+
end_time=task.end_time,
|
|
38
|
+
status=task.status,
|
|
39
|
+
initial_request_text=task.initial_request_text,
|
|
40
|
+
total_input_tokens=task.total_input_tokens,
|
|
41
|
+
total_output_tokens=task.total_output_tokens,
|
|
42
|
+
total_cached_input_tokens=task.total_cached_input_tokens,
|
|
43
|
+
token_usage_details=task.token_usage_details,
|
|
44
|
+
)
|
|
45
|
+
self.db.add(model)
|
|
46
|
+
|
|
47
|
+
self.db.commit()
|
|
48
|
+
self.db.refresh(model)
|
|
49
|
+
return self._task_model_to_entity(model)
|
|
50
|
+
|
|
51
|
+
def save_event(self, event: TaskEvent) -> TaskEvent:
|
|
52
|
+
"""Save a task event."""
|
|
53
|
+
model = TaskEventModel(
|
|
54
|
+
id=event.id,
|
|
55
|
+
task_id=event.task_id,
|
|
56
|
+
user_id=event.user_id,
|
|
57
|
+
created_time=event.created_time,
|
|
58
|
+
topic=event.topic,
|
|
59
|
+
direction=event.direction,
|
|
60
|
+
payload=event.payload,
|
|
61
|
+
)
|
|
62
|
+
self.db.add(model)
|
|
63
|
+
self.db.commit()
|
|
64
|
+
self.db.refresh(model)
|
|
65
|
+
return self._event_model_to_entity(model)
|
|
66
|
+
|
|
67
|
+
def find_by_id(self, task_id: str) -> Task | None:
|
|
68
|
+
"""Find a task by its ID."""
|
|
69
|
+
model = self.db.query(TaskModel).filter(TaskModel.id == task_id).first()
|
|
70
|
+
return self._task_model_to_entity(model) if model else None
|
|
71
|
+
|
|
72
|
+
def find_by_id_with_events(
|
|
73
|
+
self, task_id: str
|
|
74
|
+
) -> tuple[Task, list[TaskEvent]] | None:
|
|
75
|
+
"""Find a task with all its events."""
|
|
76
|
+
task_model = self.db.query(TaskModel).filter(TaskModel.id == task_id).first()
|
|
77
|
+
if not task_model:
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
event_models = (
|
|
81
|
+
self.db.query(TaskEventModel)
|
|
82
|
+
.filter(TaskEventModel.task_id == task_id)
|
|
83
|
+
.order_by(TaskEventModel.created_time.asc())
|
|
84
|
+
.all()
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
task = self._task_model_to_entity(task_model)
|
|
88
|
+
events = [self._event_model_to_entity(model) for model in event_models]
|
|
89
|
+
return task, events
|
|
90
|
+
|
|
91
|
+
def search(
|
|
92
|
+
self,
|
|
93
|
+
user_id: UserId,
|
|
94
|
+
start_date: int | None = None,
|
|
95
|
+
end_date: int | None = None,
|
|
96
|
+
search_query: str | None = None,
|
|
97
|
+
pagination: PaginationParams | None = None,
|
|
98
|
+
) -> list[Task]:
|
|
99
|
+
"""Search for tasks with filters."""
|
|
100
|
+
query = self.db.query(TaskModel)
|
|
101
|
+
if user_id != "*": # Allow wildcard for admin/system searches
|
|
102
|
+
query = query.filter(TaskModel.user_id == user_id)
|
|
103
|
+
|
|
104
|
+
if start_date:
|
|
105
|
+
query = query.filter(TaskModel.start_time >= start_date)
|
|
106
|
+
if end_date:
|
|
107
|
+
query = query.filter(TaskModel.start_time <= end_date)
|
|
108
|
+
if search_query:
|
|
109
|
+
query = query.filter(
|
|
110
|
+
TaskModel.initial_request_text.ilike(f"%{search_query}%")
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
query = query.order_by(TaskModel.start_time.desc())
|
|
114
|
+
|
|
115
|
+
if pagination:
|
|
116
|
+
offset = (pagination.page - 1) * pagination.page_size
|
|
117
|
+
query = query.offset(offset).limit(pagination.page_size)
|
|
118
|
+
|
|
119
|
+
models = query.all()
|
|
120
|
+
return [self._task_model_to_entity(model) for model in models]
|
|
121
|
+
|
|
122
|
+
def delete_tasks_older_than(self, cutoff_time_ms: int, batch_size: int) -> int:
|
|
123
|
+
"""
|
|
124
|
+
Delete tasks (and their events via cascade) older than the cutoff time.
|
|
125
|
+
Uses batch deletion to avoid long-running transactions.
|
|
126
|
+
|
|
127
|
+
Args:
|
|
128
|
+
cutoff_time_ms: Epoch milliseconds - tasks with start_time before this will be deleted
|
|
129
|
+
batch_size: Number of tasks to delete per batch
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
Total number of tasks deleted
|
|
133
|
+
"""
|
|
134
|
+
total_deleted = 0
|
|
135
|
+
|
|
136
|
+
while True:
|
|
137
|
+
# Find a batch of task IDs to delete
|
|
138
|
+
task_ids_to_delete = (
|
|
139
|
+
self.db.query(TaskModel.id)
|
|
140
|
+
.filter(TaskModel.start_time < cutoff_time_ms)
|
|
141
|
+
.limit(batch_size)
|
|
142
|
+
.all()
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
if not task_ids_to_delete:
|
|
146
|
+
break
|
|
147
|
+
|
|
148
|
+
# Extract IDs from the result tuples
|
|
149
|
+
ids = [task_id[0] for task_id in task_ids_to_delete]
|
|
150
|
+
|
|
151
|
+
# Delete this batch
|
|
152
|
+
deleted_count = (
|
|
153
|
+
self.db.query(TaskModel)
|
|
154
|
+
.filter(TaskModel.id.in_(ids))
|
|
155
|
+
.delete(synchronize_session=False)
|
|
156
|
+
)
|
|
157
|
+
|
|
158
|
+
self.db.commit()
|
|
159
|
+
total_deleted += deleted_count
|
|
160
|
+
|
|
161
|
+
# If we deleted fewer than batch_size, we're done
|
|
162
|
+
if deleted_count < batch_size:
|
|
163
|
+
break
|
|
164
|
+
|
|
165
|
+
return total_deleted
|
|
166
|
+
|
|
167
|
+
def _task_model_to_entity(self, model: TaskModel) -> Task:
|
|
168
|
+
"""Convert SQLAlchemy task model to domain entity."""
|
|
169
|
+
return Task.model_validate(model)
|
|
170
|
+
|
|
171
|
+
def _event_model_to_entity(self, model: TaskEventModel) -> TaskEvent:
|
|
172
|
+
"""Convert SQLAlchemy event model to domain entity."""
|
|
173
|
+
return TaskEvent.model_validate(model)
|
|
@@ -860,7 +860,7 @@ async def upload_artifact(
|
|
|
860
860
|
f"[ArtifactRouter:Post:{filename}] User={user_id}, Session={session_id} -"
|
|
861
861
|
)
|
|
862
862
|
log.info(
|
|
863
|
-
"%s Request received. Upload filename: '%s', content type: %s
|
|
863
|
+
"%s Request received. Upload filename: '%s', content type: %s",
|
|
864
864
|
log_prefix,
|
|
865
865
|
upload_file.filename,
|
|
866
866
|
upload_file.content_type,
|
|
@@ -27,6 +27,30 @@ async def get_app_config(
|
|
|
27
27
|
log_prefix = "[GET /api/v1/config] "
|
|
28
28
|
log.info("%sRequest received.", log_prefix)
|
|
29
29
|
try:
|
|
30
|
+
# Start with explicitly defined feature flags
|
|
31
|
+
feature_enablement = component.get_config("frontend_feature_enablement", {})
|
|
32
|
+
|
|
33
|
+
# Manually check for the task_logging feature and add it
|
|
34
|
+
task_logging_config = component.get_config("task_logging", {})
|
|
35
|
+
if task_logging_config and task_logging_config.get("enabled", False):
|
|
36
|
+
feature_enablement["taskLogging"] = True
|
|
37
|
+
log.debug("%s taskLogging feature flag is enabled.", log_prefix)
|
|
38
|
+
|
|
39
|
+
# Determine if feedback should be enabled
|
|
40
|
+
# Feedback requires SQL session storage for persistence
|
|
41
|
+
feedback_enabled = component.get_config("frontend_collect_feedback", False)
|
|
42
|
+
if feedback_enabled:
|
|
43
|
+
session_config = component.get_config("session_service", {})
|
|
44
|
+
session_type = session_config.get("type", "memory")
|
|
45
|
+
if session_type != "sql":
|
|
46
|
+
log.warning(
|
|
47
|
+
"%s Feedback is configured but session_service type is '%s' (not 'sql'). "
|
|
48
|
+
"Disabling feedback for frontend.",
|
|
49
|
+
log_prefix,
|
|
50
|
+
session_type
|
|
51
|
+
)
|
|
52
|
+
feedback_enabled = False
|
|
53
|
+
|
|
30
54
|
config_data = {
|
|
31
55
|
"frontend_server_url": "",
|
|
32
56
|
"frontend_auth_login_url": component.get_config(
|
|
@@ -39,11 +63,9 @@ async def get_app_config(
|
|
|
39
63
|
"frontend_welcome_message", ""
|
|
40
64
|
),
|
|
41
65
|
"frontend_redirect_url": component.get_config("frontend_redirect_url", ""),
|
|
42
|
-
"frontend_collect_feedback":
|
|
43
|
-
"frontend_collect_feedback", False
|
|
44
|
-
),
|
|
66
|
+
"frontend_collect_feedback": feedback_enabled,
|
|
45
67
|
"frontend_bot_name": component.get_config("frontend_bot_name", "A2A Agent"),
|
|
46
|
-
"frontend_feature_enablement":
|
|
68
|
+
"frontend_feature_enablement": feature_enablement,
|
|
47
69
|
"persistence_enabled": api_config.get("persistence_enabled", False),
|
|
48
70
|
}
|
|
49
71
|
log.info("%sReturning frontend configuration.", log_prefix)
|
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# DEVELOPER GUIDE: dto
|
|
2
|
+
|
|
3
|
+
## Quick Summary
|
|
4
|
+
The `dto` directory contains Data Transfer Objects (DTOs) for API contract definition and validation in the HTTP SSE gateway. It's organized into two main subdirectories: `requests` for incoming API request validation using Pydantic models, and `responses` for structured API response formatting with automatic timestamp conversion. The DTOs primarily focus on session management operations and provide type-safe interfaces for API endpoints.
|
|
5
|
+
|
|
6
|
+
## Files and Subdirectories Overview
|
|
7
|
+
- **Direct files:**
|
|
8
|
+
- `__init__.py` - Main module exports for requests and responses submodules
|
|
9
|
+
- **Subdirectories:**
|
|
10
|
+
- `requests/` - Request DTOs for API endpoint validation (session CRUD operations)
|
|
11
|
+
- `responses/` - Response DTOs with automatic timestamp serialization and field aliasing
|
|
12
|
+
|
|
13
|
+
## Developer API Reference
|
|
14
|
+
|
|
15
|
+
### Direct Files
|
|
16
|
+
|
|
17
|
+
#### __init__.py
|
|
18
|
+
**Purpose:** Main entry point that exports the requests and responses submodules
|
|
19
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.routers.dto import requests, responses`
|
|
20
|
+
|
|
21
|
+
**Exports:**
|
|
22
|
+
- `requests` - Module containing all request DTOs
|
|
23
|
+
- `responses` - Module containing all response DTOs
|
|
24
|
+
|
|
25
|
+
### Subdirectory APIs
|
|
26
|
+
|
|
27
|
+
#### requests/
|
|
28
|
+
**Purpose:** Provides Pydantic models for validating incoming API requests, specifically for session management operations
|
|
29
|
+
**Key Exports:** GetSessionsRequest, GetSessionRequest, GetSessionHistoryRequest, UpdateSessionRequest, DeleteSessionRequest
|
|
30
|
+
**Import Examples:**
|
|
31
|
+
```python
|
|
32
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.requests import (
|
|
33
|
+
GetSessionRequest,
|
|
34
|
+
GetSessionHistoryRequest,
|
|
35
|
+
UpdateSessionRequest
|
|
36
|
+
)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### responses/
|
|
40
|
+
**Purpose:** Provides structured response DTOs with automatic timestamp conversion and field aliasing for API consistency
|
|
41
|
+
**Key Exports:** MessageResponse, SessionResponse, SessionListResponse, BaseTimestampResponse
|
|
42
|
+
**Import Examples:**
|
|
43
|
+
```python
|
|
44
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.responses import (
|
|
45
|
+
MessageResponse,
|
|
46
|
+
SessionResponse,
|
|
47
|
+
SessionListResponse
|
|
48
|
+
)
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Complete Usage Guide
|
|
52
|
+
|
|
53
|
+
### 1. Basic Imports and Setup
|
|
54
|
+
|
|
55
|
+
```python
|
|
56
|
+
# Import the main dto modules
|
|
57
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto import requests, responses
|
|
58
|
+
|
|
59
|
+
# Or import specific DTOs directly
|
|
60
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.requests import (
|
|
61
|
+
GetSessionRequest,
|
|
62
|
+
GetSessionHistoryRequest,
|
|
63
|
+
UpdateSessionRequest
|
|
64
|
+
)
|
|
65
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.responses import (
|
|
66
|
+
SessionResponse,
|
|
67
|
+
MessageResponse,
|
|
68
|
+
SessionListResponse
|
|
69
|
+
)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 2. Working with Request DTOs
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.requests import (
|
|
76
|
+
GetSessionRequest,
|
|
77
|
+
GetSessionHistoryRequest,
|
|
78
|
+
UpdateSessionRequest
|
|
79
|
+
)
|
|
80
|
+
from pydantic import ValidationError
|
|
81
|
+
|
|
82
|
+
# Create a request to get a specific session
|
|
83
|
+
def get_session(session_id: str, user_id: str):
|
|
84
|
+
try:
|
|
85
|
+
request = GetSessionRequest(
|
|
86
|
+
session_id=session_id,
|
|
87
|
+
user_id=user_id
|
|
88
|
+
)
|
|
89
|
+
return request
|
|
90
|
+
except ValidationError as e:
|
|
91
|
+
print(f"Invalid request parameters: {e}")
|
|
92
|
+
return None
|
|
93
|
+
|
|
94
|
+
# Create a request to get session history with pagination
|
|
95
|
+
def get_session_history(session_id: str, user_id: str, page: int = 1, size: int = 20):
|
|
96
|
+
try:
|
|
97
|
+
request = GetSessionHistoryRequest(
|
|
98
|
+
session_id=session_id,
|
|
99
|
+
user_id=user_id,
|
|
100
|
+
pagination={"page": page, "size": size}
|
|
101
|
+
)
|
|
102
|
+
return request
|
|
103
|
+
except ValidationError as e:
|
|
104
|
+
print(f"Validation failed: {e}")
|
|
105
|
+
return None
|
|
106
|
+
|
|
107
|
+
# Create a request to update session name
|
|
108
|
+
def update_session_name(session_id: str, user_id: str, new_name: str):
|
|
109
|
+
try:
|
|
110
|
+
request = UpdateSessionRequest(
|
|
111
|
+
session_id=session_id,
|
|
112
|
+
user_id=user_id,
|
|
113
|
+
name=new_name # Automatically validated (1-255 characters)
|
|
114
|
+
)
|
|
115
|
+
return request
|
|
116
|
+
except ValidationError as e:
|
|
117
|
+
print(f"Validation failed: {e}")
|
|
118
|
+
return None
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### 3. Working with Response DTOs
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.responses import (
|
|
125
|
+
SessionResponse,
|
|
126
|
+
MessageResponse,
|
|
127
|
+
SessionListResponse
|
|
128
|
+
)
|
|
129
|
+
from solace_agent_mesh.gateway.http_sse.shared.enums import MessageType, SenderType
|
|
130
|
+
import time
|
|
131
|
+
|
|
132
|
+
# Create session responses
|
|
133
|
+
def create_session_response(session_data: dict) -> SessionResponse:
|
|
134
|
+
return SessionResponse(
|
|
135
|
+
id=session_data["id"],
|
|
136
|
+
user_id=session_data["user_id"],
|
|
137
|
+
name=session_data.get("name"),
|
|
138
|
+
agent_id=session_data.get("agent_id"),
|
|
139
|
+
created_time=int(time.time() * 1000), # Current time in epoch ms
|
|
140
|
+
updated_time=session_data.get("updated_time")
|
|
141
|
+
)
|
|
142
|
+
|
|
143
|
+
# Create message responses
|
|
144
|
+
def create_message_response(message_data: dict) -> MessageResponse:
|
|
145
|
+
return MessageResponse(
|
|
146
|
+
id=message_data["id"],
|
|
147
|
+
session_id=message_data["session_id"],
|
|
148
|
+
message=message_data["message"],
|
|
149
|
+
sender_type=SenderType.USER,
|
|
150
|
+
sender_name=message_data["sender_name"],
|
|
151
|
+
message_type=MessageType.TEXT,
|
|
152
|
+
created_time=int(time.time() * 1000)
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
# Create paginated session list responses
|
|
156
|
+
def create_session_list_response(sessions: list, total: int) -> SessionListResponse:
|
|
157
|
+
session_responses = [create_session_response(session) for session in sessions]
|
|
158
|
+
return SessionListResponse(
|
|
159
|
+
sessions=session_responses,
|
|
160
|
+
pagination={"page": 1, "size": len(sessions), "total_pages": 1},
|
|
161
|
+
total_count=total
|
|
162
|
+
)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### 4. Complete API Endpoint Example
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
from fastapi import APIRouter, HTTPException
|
|
169
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.requests import (
|
|
170
|
+
GetSessionRequest,
|
|
171
|
+
GetSessionHistoryRequest,
|
|
172
|
+
UpdateSessionRequest
|
|
173
|
+
)
|
|
174
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.responses import (
|
|
175
|
+
SessionResponse,
|
|
176
|
+
MessageResponse,
|
|
177
|
+
SessionListResponse
|
|
178
|
+
)
|
|
179
|
+
|
|
180
|
+
router = APIRouter()
|
|
181
|
+
|
|
182
|
+
@router.get("/sessions/{session_id}")
|
|
183
|
+
async def get_session(session_id: str, user_id: str) -> SessionResponse:
|
|
184
|
+
"""Get a specific session"""
|
|
185
|
+
|
|
186
|
+
# Create and validate request DTO
|
|
187
|
+
request = GetSessionRequest(
|
|
188
|
+
session_id=session_id,
|
|
189
|
+
user_id=user_id
|
|
190
|
+
)
|
|
191
|
+
|
|
192
|
+
# Fetch data (mock implementation)
|
|
193
|
+
session_data = fetch_session(request)
|
|
194
|
+
|
|
195
|
+
# Return structured response with automatic timestamp conversion
|
|
196
|
+
return SessionResponse(
|
|
197
|
+
id=session_data["id"],
|
|
198
|
+
user_id=session_data["user_id"],
|
|
199
|
+
name=session_data["name"],
|
|
200
|
+
created_time=session_data["created_time"]
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
@router.get("/sessions/{session_id}/history")
|
|
204
|
+
async def get_session_history(
|
|
205
|
+
session_id: str,
|
|
206
|
+
user_id: str,
|
|
207
|
+
page: int = 1,
|
|
208
|
+
size: int = 20
|
|
209
|
+
) -> list[MessageResponse]:
|
|
210
|
+
"""Get session message history"""
|
|
211
|
+
|
|
212
|
+
# Validate request using DTO
|
|
213
|
+
request = GetSessionHistoryRequest(
|
|
214
|
+
session_id=session_id,
|
|
215
|
+
user_id=user_id,
|
|
216
|
+
pagination={"page": page, "size": size}
|
|
217
|
+
)
|
|
218
|
+
|
|
219
|
+
# Fetch messages (mock implementation)
|
|
220
|
+
messages_data = fetch_session_messages(request)
|
|
221
|
+
|
|
222
|
+
# Return response DTOs with automatic field aliasing
|
|
223
|
+
return [
|
|
224
|
+
MessageResponse(
|
|
225
|
+
id=msg["id"],
|
|
226
|
+
session_id=msg["session_id"],
|
|
227
|
+
message=msg["message"],
|
|
228
|
+
sender_type=msg["sender_type"],
|
|
229
|
+
sender_name=msg["sender_name"],
|
|
230
|
+
message_type=msg["message_type"],
|
|
231
|
+
created_time=msg["created_time"]
|
|
232
|
+
)
|
|
233
|
+
for msg in messages_data
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
@router.put("/sessions/{session_id}")
|
|
237
|
+
async def update_session(
|
|
238
|
+
session_id: str,
|
|
239
|
+
user_id: str,
|
|
240
|
+
name: str
|
|
241
|
+
) -> SessionResponse:
|
|
242
|
+
"""Update session name"""
|
|
243
|
+
|
|
244
|
+
# Validate request using DTO
|
|
245
|
+
try:
|
|
246
|
+
request = UpdateSessionRequest(
|
|
247
|
+
session_id=session_id,
|
|
248
|
+
user_id=user_id,
|
|
249
|
+
name=name
|
|
250
|
+
)
|
|
251
|
+
except ValidationError as e:
|
|
252
|
+
raise HTTPException(status_code=400, detail=str(e))
|
|
253
|
+
|
|
254
|
+
# Update session (mock implementation)
|
|
255
|
+
updated_session = update_session_in_db(request)
|
|
256
|
+
|
|
257
|
+
# Return response DTO with automatic field aliasing
|
|
258
|
+
return SessionResponse(
|
|
259
|
+
id=updated_session["id"],
|
|
260
|
+
user_id=updated_session["user_id"],
|
|
261
|
+
name=updated_session["name"],
|
|
262
|
+
created_time=updated_session["created_time"],
|
|
263
|
+
updated_time=updated_session["updated_time"]
|
|
264
|
+
)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### 5. JSON Serialization with Automatic Timestamp Conversion
|
|
268
|
+
|
|
269
|
+
```python
|
|
270
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.responses import SessionResponse, MessageResponse
|
|
271
|
+
from solace_agent_mesh.gateway.http_sse.shared.enums import MessageType, SenderType
|
|
272
|
+
import json
|
|
273
|
+
|
|
274
|
+
# Create a session response
|
|
275
|
+
session = SessionResponse(
|
|
276
|
+
id="sess_123",
|
|
277
|
+
user_id="user_456",
|
|
278
|
+
name="My Session",
|
|
279
|
+
created_time=1640995200000, # Epoch milliseconds
|
|
280
|
+
updated_time=1640995260000
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# Automatic conversion to ISO strings in JSON output
|
|
284
|
+
json_output = session.model_dump_json()
|
|
285
|
+
print(json_output)
|
|
286
|
+
# Output: {
|
|
287
|
+
# "id": "sess_123",
|
|
288
|
+
# "userId": "user_456", # Note the camelCase aliasing
|
|
289
|
+
# "name": "My Session",
|
|
290
|
+
# "createdTime": "2022-01-01T00:00:00Z", # Converted to ISO string
|
|
291
|
+
# "updatedTime": "2022-01-01T00:01:00Z"
|
|
292
|
+
# }
|
|
293
|
+
|
|
294
|
+
# Create a message response with field aliasing
|
|
295
|
+
message = MessageResponse(
|
|
296
|
+
id="msg_789",
|
|
297
|
+
session_id="sess_123",
|
|
298
|
+
message="Hello world",
|
|
299
|
+
sender_type=SenderType.USER,
|
|
300
|
+
sender_name="John Doe",
|
|
301
|
+
message_type=MessageType.TEXT,
|
|
302
|
+
created_time=1640995200000
|
|
303
|
+
)
|
|
304
|
+
|
|
305
|
+
# Get dict with converted timestamps and aliased fields
|
|
306
|
+
dict_output = message.model_dump()
|
|
307
|
+
print(dict_output["sessionId"]) # "sess_123" (camelCase alias)
|
|
308
|
+
print(dict_output["senderType"]) # SenderType.USER (camelCase alias)
|
|
309
|
+
print(dict_output["createdTime"]) # "2022-01-01T00:00:00Z" (converted timestamp)
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
### 6. Custom Response Classes Using Base
|
|
313
|
+
|
|
314
|
+
```python
|
|
315
|
+
from solace_agent_mesh.gateway.http_sse.routers.dto.responses.base_responses import BaseTimestampResponse
|
|
316
|
+
|
|
317
|
+
class CustomResponse(BaseTimestampResponse):
|
|
318
|
+
"""Custom response with automatic timestamp handling"""
|
|
319
|
+
name: str
|
|
320
|
+
status: str
|
|
321
|
+
created_time: int
|
|
322
|
+
last_accessed: int | None = None
|
|
323
|
+
|
|
324
|
+
class Config:
|
|
325
|
+
# Add field aliases if needed
|
|
326
|
+
alias_generator = lambda field_name: ''.join(
|
|
327
|
+
word.capitalize() if i > 0 else word
|
|
328
|
+
for i, word in enumerate(field_name.split('_'))
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
# Usage
|
|
332
|
+
custom_response = CustomResponse(
|
|
333
|
+
name="Test Item",
|
|
334
|
+
status="active",
|
|
335
|
+
created_time=1640995200000,
|
|
336
|
+
last_accessed=1640995300000
|
|
337
|
+
)
|
|
338
|
+
|
|
339
|
+
# Automatic timestamp conversion in JSON
|
|
340
|
+
json_data = custom_response.model_dump_json()
|
|
341
|
+
# Fields like created_time become ISO strings automatically
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
This comprehensive guide shows how the `dto` directory provides a complete type-safe API contract system with automatic validation for requests and structured responses with timestamp conversion for the HTTP SSE gateway.
|
|
345
|
+
|
|
346
|
+
# content_hash: 3bb29d4c46b962221fc3034560b7e0da75b5a41f7f8f4d4f25aecf26e10f83f5
|
|
@@ -4,12 +4,12 @@ Request DTOs for API endpoints.
|
|
|
4
4
|
|
|
5
5
|
from .session_requests import (
|
|
6
6
|
GetSessionRequest,
|
|
7
|
-
GetSessionHistoryRequest,
|
|
8
7
|
UpdateSessionRequest,
|
|
9
8
|
)
|
|
9
|
+
from .task_requests import SaveTaskRequest
|
|
10
10
|
|
|
11
11
|
__all__ = [
|
|
12
12
|
"GetSessionRequest",
|
|
13
|
-
"GetSessionHistoryRequest",
|
|
14
13
|
"UpdateSessionRequest",
|
|
15
|
-
|
|
14
|
+
"SaveTaskRequest",
|
|
15
|
+
]
|