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.

Files changed (181) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +3 -4
  2. solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
  3. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
  4. solace_agent_mesh/agent/adk/callbacks.py +51 -2
  5. solace_agent_mesh/agent/adk/models/lite_llm.py +1 -0
  6. solace_agent_mesh/agent/adk/models/models_llm.txt +1 -2
  7. solace_agent_mesh/agent/agent_llm.txt +1 -1
  8. solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
  9. solace_agent_mesh/agent/protocol/event_handlers.py +2 -13
  10. solace_agent_mesh/agent/protocol/protocol_llm.txt +15 -2
  11. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
  12. solace_agent_mesh/agent/sac/component.py +51 -21
  13. solace_agent_mesh/agent/sac/sac_llm.txt +15 -1
  14. solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
  15. solace_agent_mesh/agent/sac/task_execution_context.py +73 -0
  16. solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
  17. solace_agent_mesh/agent/tools/tools_llm.txt +148 -154
  18. solace_agent_mesh/agent/tools/tools_llm_detail.txt +274 -0
  19. solace_agent_mesh/agent/utils/utils_llm.txt +1 -1
  20. solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
  21. solace_agent_mesh/assets/docs/404.html +3 -3
  22. solace_agent_mesh/assets/docs/assets/js/483cef9a.bf9398af.js +1 -0
  23. solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js → main.0c149855.js} +2 -2
  24. solace_agent_mesh/assets/docs/assets/js/{runtime~main.40527046.js → runtime~main.c66557e4.js} +1 -1
  25. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +3 -3
  26. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +3 -3
  27. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +8 -4
  28. 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
  29. solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +3 -3
  30. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +3 -3
  31. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
  32. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +3 -3
  33. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +3 -3
  34. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
  35. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +3 -3
  36. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +3 -3
  37. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
  38. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
  39. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +3 -3
  40. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
  41. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +3 -3
  42. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +3 -3
  43. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  44. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +3 -3
  45. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +3 -3
  46. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +3 -3
  47. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +3 -3
  48. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +3 -3
  49. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +3 -3
  50. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +3 -3
  51. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +3 -3
  52. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +3 -3
  53. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +3 -3
  54. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +3 -3
  55. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +3 -3
  56. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +3 -3
  57. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
  58. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +3 -3
  59. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +3 -3
  60. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +3 -3
  61. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +3 -3
  62. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +3 -3
  63. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
  64. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +3 -3
  65. solace_agent_mesh/assets/docs/lunr-index-1760032255022.json +1 -0
  66. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  67. solace_agent_mesh/assets/docs/search-doc-1760032255022.json +1 -0
  68. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  69. solace_agent_mesh/cli/__init__.py +1 -1
  70. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-j1LW-wlq.js → authCallback-DwrxZE0E.js} +1 -1
  71. solace_agent_mesh/client/webui/frontend/static/assets/{client-B9p_nFNA.js → client-DarGQzyw.js} +1 -1
  72. solace_agent_mesh/client/webui/frontend/static/assets/main-CZbpmwfA.css +1 -0
  73. solace_agent_mesh/client/webui/frontend/static/assets/main-C__uuUkB.js +339 -0
  74. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CS5YMf8a.js → vendor-BKIeiHj_.js} +80 -70
  75. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  76. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  77. solace_agent_mesh/common/a2a/a2a_llm.txt +1 -1
  78. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
  79. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +1 -1
  80. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
  81. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +23 -0
  82. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +93 -15
  83. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +23 -0
  84. solace_agent_mesh/common/common_llm.txt +24 -39
  85. solace_agent_mesh/common/common_llm_detail.txt +2562 -0
  86. solace_agent_mesh/common/data_parts.py +9 -1
  87. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
  88. solace_agent_mesh/common/sac/sac_llm.txt +1 -1
  89. solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
  90. solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
  91. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
  92. solace_agent_mesh/common/services/services_llm.txt +57 -6
  93. solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
  94. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
  95. solace_agent_mesh/common/utils/utils_llm.txt +75 -87
  96. solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
  97. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
  98. solace_agent_mesh/gateway/base/app.py +1 -1
  99. solace_agent_mesh/gateway/base/base_llm.txt +1 -1
  100. solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
  101. solace_agent_mesh/gateway/gateway_llm.txt +242 -235
  102. solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
  103. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +295 -0
  104. solace_agent_mesh/gateway/http_sse/alembic/env.py +10 -1
  105. solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
  106. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +155 -0
  107. solace_agent_mesh/gateway/http_sse/alembic.ini +1 -1
  108. solace_agent_mesh/gateway/http_sse/app.py +148 -2
  109. solace_agent_mesh/gateway/http_sse/component.py +368 -60
  110. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +46 -6
  111. solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +108 -0
  112. solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +1 -1
  113. solace_agent_mesh/gateway/http_sse/dependencies.py +116 -26
  114. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +172 -172
  115. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
  116. solace_agent_mesh/gateway/http_sse/main.py +146 -41
  117. solace_agent_mesh/gateway/http_sse/repository/__init__.py +3 -12
  118. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +103 -0
  119. solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +5 -3
  120. solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
  121. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +263 -0
  122. solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
  123. solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -16
  124. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +25 -0
  125. solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
  126. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +81 -0
  127. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +73 -18
  128. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -5
  129. solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
  130. solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
  131. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +266 -0
  132. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +3 -3
  133. solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
  134. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +32 -0
  135. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +340 -0
  136. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +4 -53
  137. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +173 -0
  138. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +1 -1
  139. solace_agent_mesh/gateway/http_sse/routers/config.py +26 -4
  140. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +346 -0
  141. solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +3 -3
  142. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +83 -0
  143. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +2 -10
  144. solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
  145. solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +5 -3
  146. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +107 -0
  147. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +1 -15
  148. solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
  149. solace_agent_mesh/gateway/http_sse/routers/feedback.py +37 -0
  150. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +255 -204
  151. solace_agent_mesh/gateway/http_sse/routers/sessions.py +220 -40
  152. solace_agent_mesh/gateway/http_sse/routers/tasks.py +168 -42
  153. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +272 -0
  154. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +241 -0
  155. solace_agent_mesh/gateway/http_sse/services/people_service.py +0 -80
  156. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +177 -13
  157. solace_agent_mesh/gateway/http_sse/services/session_service.py +151 -84
  158. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +317 -0
  159. solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +25 -14
  160. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +285 -0
  161. solace_agent_mesh/gateway/http_sse/shared/types.py +7 -0
  162. solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
  163. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +32 -0
  164. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
  165. solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
  166. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -0
  167. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/METADATA +1 -1
  168. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/RECORD +172 -124
  169. solace_agent_mesh/agent/adk/invocation_monitor.py +0 -295
  170. solace_agent_mesh/assets/docs/assets/js/483cef9a.4736f2d8.js +0 -1
  171. solace_agent_mesh/assets/docs/lunr-index-1759936913198.json +0 -1
  172. solace_agent_mesh/assets/docs/search-doc-1759936913198.json +0 -1
  173. solace_agent_mesh/client/webui/frontend/static/assets/main-ChRwcV89.css +0 -1
  174. solace_agent_mesh/client/webui/frontend/static/assets/main-DnnE01OM.js +0 -339
  175. solace_agent_mesh/gateway/http_sse/repository/entities/message.py +0 -41
  176. solace_agent_mesh/gateway/http_sse/repository/message_repository.py +0 -84
  177. solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +0 -45
  178. /solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js.LICENSE.txt → main.0c149855.js.LICENSE.txt} +0 -0
  179. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/WHEEL +0 -0
  180. {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/entry_points.txt +0 -0
  181. {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 Message, Session
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: PaginationInfo | None = None
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.page - 1) * pagination.page_size
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, Metadata provided: %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": component.get_config(
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": component.get_config("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
+ ]