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
@@ -1,13 +1,17 @@
1
1
  # DEVELOPER GUIDE: services
2
2
 
3
3
  ## Quick Summary
4
- The `services` directory contains the business logic layer for the HTTP SSE Gateway. It provides high-level services for agent management (discovering and retrieving A2A agents), user identity operations (searching for users), and task management (cancelling A2A tasks). These services abstract the complexities of interacting with agent registries, identity providers, and A2A messaging protocols.
4
+ The `services` directory contains the business logic layer for the HTTP SSE Gateway. It provides high-level services for agent management (discovering and retrieving A2A agents), user feedback processing with database persistence and event publishing, user search via identity services, session management with database persistence, task logging to database, data retention/cleanup, and A2A task operations like cancellation.
5
5
 
6
6
  ## Files Overview
7
7
  - `__init__.py` - Package initialization file marking the directory as a Python package
8
- - `agent_service.py` - Service for retrieving information about discovered A2A agents from the registry
8
+ - `agent_card_service.py` - Service for retrieving information about discovered A2A agents from the registry
9
+ - `data_retention_service.py` - Service for automatic cleanup of old tasks and feedback based on retention policies
10
+ - `feedback_service.py` - Service for processing and storing user feedback on chat messages with database and event publishing
9
11
  - `people_service.py` - Service for searching users via configured identity services
10
- - `task_service.py` - Service for handling A2A task cancellation operations
12
+ - `session_service.py` - Service for managing chat sessions and messages with database persistence
13
+ - `task_logger_service.py` - Service for logging A2A tasks and events to the database
14
+ - `task_service.py` - Service for handling A2A task operations like cancellation
11
15
 
12
16
  ## Developer API Reference
13
17
 
@@ -15,36 +19,107 @@ The `services` directory contains the business logic layer for the HTTP SSE Gate
15
19
  **Purpose:** Marks the services directory as a Python package
16
20
  **Import:** N/A - No public interfaces
17
21
 
18
- ### agent_service.py
22
+ ### agent_card_service.py
19
23
  **Purpose:** Provides methods for accessing information about discovered A2A agents from the shared AgentRegistry
20
- **Import:** `from solace_agent_mesh.gateway.http_sse.services.agent_service import AgentService`
24
+ **Import:** `from solace_agent_mesh.gateway.http_sse.services.agent_card_service import AgentCardService`
21
25
 
22
26
  **Classes:**
23
- - `AgentService(agent_registry: AgentRegistry)` - Service for accessing discovered A2A agent information
24
- - `get_all_agents() -> List[AgentCard]` - Retrieves all currently discovered and registered agent cards
25
- - `get_agent_by_name(agent_name: str) -> Optional[AgentCard]` - Retrieves a specific agent card by name, returns None if not found
27
+ - `AgentCardService(agent_registry: AgentRegistry)` - Service for accessing discovered A2A agent information
28
+ - `get_all_agent_cards() -> List[AgentCard]` - Retrieves all currently discovered and registered agent cards
29
+ - `get_agent_card_by_name(agent_name: str) -> Optional[AgentCard]` - Retrieves a specific agent card by name, returns None if not found
26
30
 
27
31
  **Usage Examples:**
28
32
  ```python
29
- from solace_agent_mesh.gateway.http_sse.services.agent_service import AgentService
33
+ from solace_agent_mesh.gateway.http_sse.services.agent_card_service import AgentCardService
30
34
  from solace_agent_mesh.common.agent_registry import AgentRegistry
31
35
 
32
36
  # Initialize with shared agent registry
33
37
  agent_registry = AgentRegistry() # Usually injected as shared instance
34
- agent_service = AgentService(agent_registry=agent_registry)
38
+ agent_service = AgentCardService(agent_registry=agent_registry)
35
39
 
36
40
  # Get all available agents
37
- all_agents = agent_service.get_all_agents()
41
+ all_agents = agent_service.get_all_agent_cards()
38
42
  print(f"Found {len(all_agents)} agents")
39
43
 
40
44
  # Get specific agent by name
41
- agent = agent_service.get_agent_by_name("data-processor")
45
+ agent = agent_service.get_agent_card_by_name("data-processor")
42
46
  if agent:
43
47
  print(f"Found agent: {agent.name}")
44
48
  else:
45
49
  print("Agent not found")
46
50
  ```
47
51
 
52
+ ### data_retention_service.py
53
+ **Purpose:** Service for automatically cleaning up old tasks, task events, and feedback based on configurable retention policies
54
+ **Import:** `from solace_agent_mesh.gateway.http_sse.services.data_retention_service import DataRetentionService`
55
+
56
+ **Classes:**
57
+ - `DataRetentionService(session_factory: Callable[[], DBSession] | None, config: Dict[str, Any])` - Service for automatic data cleanup based on retention policies
58
+ - `cleanup_old_data() -> None` - Main orchestration method for cleaning up old data, calls cleanup methods for tasks and feedback
59
+
60
+ **Constants/Variables:**
61
+ - `MIN_RETENTION_DAYS: int` - Minimum retention period (7 days)
62
+ - `MIN_CLEANUP_INTERVAL_HOURS: int` - Minimum cleanup interval (1 hour)
63
+ - `MIN_BATCH_SIZE: int` - Minimum batch size for deletion (1)
64
+ - `MAX_BATCH_SIZE: int` - Maximum batch size for deletion (10000)
65
+
66
+ **Usage Examples:**
67
+ ```python
68
+ from solace_agent_mesh.gateway.http_sse.services.data_retention_service import DataRetentionService
69
+ from sqlalchemy.orm import sessionmaker
70
+
71
+ # Initialize with database session factory and config
72
+ session_factory = sessionmaker(bind=your_engine)
73
+ config = {
74
+ "enabled": True,
75
+ "task_retention_days": 90,
76
+ "feedback_retention_days": 90,
77
+ "cleanup_interval_hours": 24,
78
+ "batch_size": 1000
79
+ }
80
+
81
+ retention_service = DataRetentionService(
82
+ session_factory=session_factory,
83
+ config=config
84
+ )
85
+
86
+ # Run cleanup (typically called by scheduler)
87
+ retention_service.cleanup_old_data()
88
+ ```
89
+
90
+ ### feedback_service.py
91
+ **Purpose:** Handles the business logic for processing and storing user feedback with database persistence and event publishing
92
+ **Import:** `from solace_agent_mesh.gateway.http_sse.services.feedback_service import FeedbackService`
93
+
94
+ **Classes:**
95
+ - `FeedbackService(session_factory: Callable[[], DBSession] | None, component: WebUIBackendComponent, task_repo: ITaskRepository)` - Service for processing user feedback with database persistence and event publishing
96
+ - `process_feedback(payload: FeedbackPayload, user_id: str) -> None` - Asynchronously processes and stores feedback, publishes events if configured
97
+
98
+ **Usage Examples:**
99
+ ```python
100
+ import asyncio
101
+ from solace_agent_mesh.gateway.http_sse.services.feedback_service import FeedbackService
102
+ from sqlalchemy.orm import sessionmaker
103
+
104
+ # Initialize with database session factory
105
+ session_factory = sessionmaker(bind=your_engine)
106
+ component = YourWebUIBackendComponent() # Your component instance
107
+ task_repo = YourTaskRepository() # Your task repository
108
+
109
+ feedback_service = FeedbackService(
110
+ session_factory=session_factory,
111
+ component=component,
112
+ task_repo=task_repo
113
+ )
114
+
115
+ # Process feedback (requires FeedbackPayload from router)
116
+ async def process_user_feedback():
117
+ # payload would be a FeedbackPayload instance from the router
118
+ await feedback_service.process_feedback(payload, user_id="user123")
119
+
120
+ asyncio.run(process_user_feedback())
121
+ ```
122
+
48
123
  ### people_service.py
49
124
  **Purpose:** Provides user search functionality via configured identity services
50
125
  **Import:** `from solace_agent_mesh.gateway.http_sse.services.people_service import PeopleService`
@@ -76,6 +151,95 @@ people_service_no_id = PeopleService(identity_service=None)
76
151
  asyncio.run(search_users())
77
152
  ```
78
153
 
154
+ ### session_service.py
155
+ **Purpose:** Manages chat sessions and messages with database persistence support
156
+ **Import:** `from solace_agent_mesh.gateway.http_sse.services.session_service import SessionService`
157
+
158
+ **Classes:**
159
+ - `SessionService(component: WebUIBackendComponent = None)` - Service for managing chat sessions and messages
160
+ - `is_persistence_enabled() -> bool` - Checks if the service is configured with a persistent backend
161
+ - `get_user_sessions(db: DbSession, user_id: UserId, pagination: PaginationParams | None = None) -> PaginatedResponse[Session]` - Retrieves paginated sessions for a user
162
+ - `get_session_details(db: DbSession, session_id: SessionId, user_id: UserId) -> Session | None` - Gets session details for a specific session
163
+ - `get_session_history(db: DbSession, session_id: SessionId, user_id: UserId, pagination: PaginationInfo | None = None) -> SessionHistory | None` - Gets session with messages
164
+ - `create_session(db: DbSession, user_id: UserId, name: str | None = None, agent_id: str | None = None, session_id: str | None = None) -> Optional[Session]` - Creates a new session
165
+ - `update_session_name(db: DbSession, session_id: SessionId, user_id: UserId, name: str) -> Session | None` - Updates session name
166
+ - `delete_session_with_notifications(db: DbSession, session_id: SessionId, user_id: UserId) -> bool` - Deletes session and notifies agents
167
+ - `add_message_to_session(db: DbSession, session_id: SessionId, user_id: UserId, message: str, sender_type: SenderType, sender_name: str, agent_id: str | None = None, message_type: MessageType = MessageType.TEXT) -> Message` - Adds a message to a session
168
+
169
+ **Usage Examples:**
170
+ ```python
171
+ from solace_agent_mesh.gateway.http_sse.services.session_service import SessionService
172
+ from solace_agent_mesh.gateway.http_sse.shared.enums import SenderType, MessageType
173
+ from sqlalchemy.orm import Session as DbSession
174
+
175
+ # Initialize with component
176
+ component = YourWebUIBackendComponent() # Your component
177
+ session_service = SessionService(component=component)
178
+
179
+ # Use with database session
180
+ with your_session_factory() as db:
181
+ # Create a new session
182
+ session = session_service.create_session(
183
+ db=db,
184
+ user_id="user123",
185
+ name="My Chat Session",
186
+ agent_id="assistant-agent"
187
+ )
188
+
189
+ # Add a message to the session
190
+ message = session_service.add_message_to_session(
191
+ db=db,
192
+ session_id=session.id,
193
+ user_id="user123",
194
+ message="Hello, how can you help me?",
195
+ sender_type=SenderType.USER,
196
+ sender_name="John Doe"
197
+ )
198
+
199
+ # Get user's sessions with pagination
200
+ paginated_sessions = session_service.get_user_sessions(db, "user123")
201
+
202
+ db.commit()
203
+ ```
204
+
205
+ ### task_logger_service.py
206
+ **Purpose:** Service for logging A2A tasks and events to the database with configurable filtering and sanitization
207
+ **Import:** `from solace_agent_mesh.gateway.http_sse.services.task_logger_service import TaskLoggerService`
208
+
209
+ **Classes:**
210
+ - `TaskLoggerService(session_factory: Callable[[], DBSession] | None, config: Dict[str, Any])` - Service for logging A2A tasks and events to database
211
+ - `log_event(event_data: Dict[str, Any]) -> None` - Parses a raw A2A message and logs it as a task event, creates or updates master task record
212
+
213
+ **Usage Examples:**
214
+ ```python
215
+ from solace_agent_mesh.gateway.http_sse.services.task_logger_service import TaskLoggerService
216
+ from sqlalchemy.orm import sessionmaker
217
+
218
+ # Initialize with database session factory and config
219
+ session_factory = sessionmaker(bind=your_engine)
220
+ config = {
221
+ "enabled": True,
222
+ "log_status_updates": True,
223
+ "log_artifact_events": False,
224
+ "log_file_parts": True,
225
+ "max_file_part_size_bytes": 102400
226
+ }
227
+
228
+ task_logger = TaskLoggerService(
229
+ session_factory=session_factory,
230
+ config=config
231
+ )
232
+
233
+ # Log an A2A event
234
+ event_data = {
235
+ "topic": "sam/agents/my-agent/request",
236
+ "payload": {"id": "task-123", "method": "sendMessage"},
237
+ "user_properties": {"userId": "user@example.com"}
238
+ }
239
+
240
+ task_logger.log_event(event_data)
241
+ ```
242
+
79
243
  ### task_service.py
80
244
  **Purpose:** Handles A2A task operations, specifically task cancellation using CoreA2AService and message publishing
81
245
  **Import:** `from solace_agent_mesh.gateway.http_sse.services.task_service import TaskService, PublishFunc`
@@ -130,4 +294,4 @@ async def cancel_task_example():
130
294
  asyncio.run(cancel_task_example())
131
295
  ```
132
296
 
133
- # content_hash: 83ddf6b403dc50598ed550e4b3a5445f832b3956dad75f7a3fbbb7e6e5c6c115
297
+ # content_hash: 12385f5117d2f5c30f0e44a0913ea91d62722aa82eb55268ae6bd317311ec5eb
@@ -1,18 +1,17 @@
1
1
  import uuid
2
- from typing import TYPE_CHECKING, Optional
2
+ from typing import TYPE_CHECKING, Optional, List, Dict, Any
3
3
 
4
4
  from solace_ai_connector.common.log import log
5
5
  from sqlalchemy.orm import Session as DbSession
6
6
 
7
7
  from ..repository import (
8
- IMessageRepository,
9
8
  ISessionRepository,
10
- Message,
11
9
  Session,
12
- SessionHistory,
13
10
  )
14
- from ..shared.enums import MessageType, SenderType
15
- from ..shared.types import PaginationInfo, SessionId, UserId
11
+ from ..repository.chat_task_repository import ChatTaskRepository
12
+ from ..repository.entities import ChatTask
13
+ from ..shared.enums import SenderType
14
+ from ..shared.types import SessionId, UserId
16
15
  from ..shared import now_epoch_ms
17
16
  from ..shared.pagination import PaginationParams, PaginatedResponse, get_pagination_or_default
18
17
 
@@ -28,11 +27,10 @@ class SessionService:
28
27
  self.component = component
29
28
 
30
29
  def _get_repositories(self, db: DbSession):
31
- """Create repositories for the given database session."""
32
- from ..repository import SessionRepository, MessageRepository
30
+ """Create session repository for the given database session."""
31
+ from ..repository import SessionRepository
33
32
  session_repository = SessionRepository(db)
34
- message_repository = MessageRepository(db)
35
- return session_repository, message_repository
33
+ return session_repository
36
34
 
37
35
  def is_persistence_enabled(self) -> bool:
38
36
  """Checks if the service is configured with a persistent backend."""
@@ -54,18 +52,10 @@ class SessionService:
54
52
  raise ValueError("User ID cannot be empty")
55
53
 
56
54
  pagination = get_pagination_or_default(pagination)
57
- session_repository, _ = self._get_repositories(db)
58
-
59
- pagination_info = PaginationInfo(
60
- page=pagination.page_number,
61
- page_size=pagination.page_size,
62
- total_items=0,
63
- total_pages=0,
64
- has_next=False,
65
- has_previous=False,
66
- )
55
+ session_repository = self._get_repositories(db)
67
56
 
68
- sessions = session_repository.find_by_user(user_id, pagination_info)
57
+ # Pass pagination params directly - repository will handle offset calculation
58
+ sessions = session_repository.find_by_user(user_id, pagination)
69
59
  total_count = session_repository.count_by_user(user_id)
70
60
 
71
61
  return PaginatedResponse.create(sessions, total_count, pagination)
@@ -76,33 +66,9 @@ class SessionService:
76
66
  if not self._is_valid_session_id(session_id):
77
67
  return None
78
68
 
79
- session_repository, _ = self._get_repositories(db)
69
+ session_repository = self._get_repositories(db)
80
70
  return session_repository.find_user_session(session_id, user_id)
81
71
 
82
- def get_session_history(
83
- self,
84
- db: DbSession,
85
- session_id: SessionId,
86
- user_id: UserId,
87
- pagination: PaginationInfo | None = None,
88
- ) -> SessionHistory | None:
89
- if not self._is_valid_session_id(session_id):
90
- return None
91
-
92
- session_repository, _ = self._get_repositories(db)
93
- result = session_repository.find_user_session_with_messages(
94
- session_id, user_id, pagination
95
- )
96
- if not result:
97
- return None
98
-
99
- session, messages = result
100
- return SessionHistory(
101
- session=session,
102
- messages=messages,
103
- total_message_count=len(messages),
104
- )
105
-
106
72
  def create_session(
107
73
  self,
108
74
  db: DbSession,
@@ -131,7 +97,7 @@ class SessionService:
131
97
  updated_time=now_ms,
132
98
  )
133
99
 
134
- session_repository, _ = self._get_repositories(db)
100
+ session_repository = self._get_repositories(db)
135
101
  created_session = session_repository.save(session)
136
102
  log.info("Created new session %s for user %s", created_session.id, user_id)
137
103
 
@@ -152,7 +118,7 @@ class SessionService:
152
118
  if len(name.strip()) > 255:
153
119
  raise ValueError("Session name cannot exceed 255 characters")
154
120
 
155
- session_repository, _ = self._get_repositories(db)
121
+ session_repository = self._get_repositories(db)
156
122
  session = session_repository.find_user_session(session_id, user_id)
157
123
  if not session:
158
124
  return None
@@ -169,7 +135,7 @@ class SessionService:
169
135
  if not self._is_valid_session_id(session_id):
170
136
  raise ValueError("Invalid session ID")
171
137
 
172
- session_repository, _ = self._get_repositories(db)
138
+ session_repository = self._get_repositories(db)
173
139
  session = session_repository.find_user_session(session_id, user_id)
174
140
  if not session:
175
141
  log.warning(
@@ -198,50 +164,151 @@ class SessionService:
198
164
 
199
165
  return True
200
166
 
201
- def add_message_to_session(
167
+ def save_task(
202
168
  self,
203
169
  db: DbSession,
204
- session_id: SessionId,
205
- user_id: UserId,
206
- message: str,
207
- sender_type: SenderType,
208
- sender_name: str,
209
- agent_id: str | None = None,
210
- message_type: MessageType = MessageType.TEXT,
211
- ) -> Message:
212
- if not self._is_valid_session_id(session_id):
213
- raise ValueError("Invalid session ID")
214
-
215
- if not message or message.strip() == "":
216
- raise ValueError("Message cannot be empty")
217
-
218
- session_repository, message_repository = self._get_repositories(db)
170
+ task_id: str,
171
+ session_id: str,
172
+ user_id: str,
173
+ user_message: Optional[str],
174
+ message_bubbles: str, # JSON string (opaque)
175
+ task_metadata: Optional[str] = None # JSON string (opaque)
176
+ ) -> ChatTask:
177
+ """
178
+ Save a complete task interaction.
179
+
180
+ Args:
181
+ db: Database session
182
+ task_id: A2A task ID
183
+ session_id: Session ID
184
+ user_id: User ID
185
+ user_message: Original user input text
186
+ message_bubbles: Array of all message bubbles displayed during this task
187
+ task_metadata: Task-level metadata (status, feedback, agent name, etc.)
188
+
189
+ Returns:
190
+ Saved ChatTask entity
191
+
192
+ Raises:
193
+ ValueError: If session not found or validation fails
194
+ """
195
+ # Validate session exists and belongs to user
196
+ session_repository = self._get_repositories(db)
219
197
  session = session_repository.find_user_session(session_id, user_id)
220
198
  if not session:
221
- session = self.create_session(
222
- db=db,
223
- user_id=user_id,
224
- agent_id=agent_id,
225
- session_id=session_id,
226
- )
227
-
228
- message_entity = Message(
229
- id=str(uuid.uuid4()),
199
+ raise ValueError(f"Session {session_id} not found for user {user_id}")
200
+
201
+ # Create task entity - pass strings directly
202
+ task = ChatTask(
203
+ id=task_id,
230
204
  session_id=session_id,
231
- message=message.strip(),
232
- sender_type=sender_type,
233
- sender_name=sender_name,
234
- message_type=message_type,
205
+ user_id=user_id,
206
+ user_message=user_message,
207
+ message_bubbles=message_bubbles, # Already a string
208
+ task_metadata=task_metadata, # Already a string
235
209
  created_time=now_epoch_ms(),
210
+ updated_time=None
236
211
  )
237
-
238
- saved_message = message_repository.save(message_entity)
239
-
212
+
213
+ # Save via repository
214
+ task_repo = ChatTaskRepository(db)
215
+ saved_task = task_repo.save(task)
216
+
217
+ # Update session activity
240
218
  session.mark_activity()
241
219
  session_repository.save(session)
220
+
221
+ log.info(f"Saved task {task_id} for session {session_id}")
222
+ return saved_task
242
223
 
243
- log.info("Added message to session %s from %s", session_id, sender_name)
244
- return saved_message
224
+ def get_session_tasks(
225
+ self,
226
+ db: DbSession,
227
+ session_id: str,
228
+ user_id: str
229
+ ) -> List[ChatTask]:
230
+ """
231
+ Get all tasks for a session.
232
+
233
+ Args:
234
+ db: Database session
235
+ session_id: Session ID
236
+ user_id: User ID
237
+
238
+ Returns:
239
+ List of ChatTask entities in chronological order
240
+
241
+ Raises:
242
+ ValueError: If session not found
243
+ """
244
+ # Validate session exists and belongs to user
245
+ session_repository = self._get_repositories(db)
246
+ session = session_repository.find_user_session(session_id, user_id)
247
+ if not session:
248
+ raise ValueError(f"Session {session_id} not found for user {user_id}")
249
+
250
+ # Load tasks
251
+ task_repo = ChatTaskRepository(db)
252
+ return task_repo.find_by_session(session_id, user_id)
253
+
254
+ def get_session_messages_from_tasks(
255
+ self,
256
+ db: DbSession,
257
+ session_id: str,
258
+ user_id: str
259
+ ) -> List[Dict[str, Any]]:
260
+ """
261
+ Get session messages by flattening task message_bubbles.
262
+ This provides backward compatibility with the old message-based API.
263
+
264
+ Args:
265
+ db: Database session
266
+ session_id: Session ID
267
+ user_id: User ID
268
+
269
+ Returns:
270
+ List of message dictionaries flattened from tasks
271
+
272
+ Raises:
273
+ ValueError: If session not found
274
+ """
275
+ # Load tasks
276
+ tasks = self.get_session_tasks(db, session_id, user_id)
277
+
278
+ # Flatten message_bubbles from all tasks
279
+ messages = []
280
+ for task in tasks:
281
+ import json
282
+ message_bubbles = json.loads(task.message_bubbles) if isinstance(task.message_bubbles, str) else task.message_bubbles
283
+
284
+ for bubble in message_bubbles:
285
+ # Determine sender type from bubble type
286
+ bubble_type = bubble.get("type", "agent")
287
+ sender_type = "user" if bubble_type == "user" else "agent"
288
+
289
+ # Get sender name
290
+ if bubble_type == "user":
291
+ sender_name = user_id
292
+ else:
293
+ # Try to get agent name from task metadata, fallback to "agent"
294
+ sender_name = "agent"
295
+ if task.task_metadata:
296
+ task_metadata = json.loads(task.task_metadata) if isinstance(task.task_metadata, str) else task.task_metadata
297
+ sender_name = task_metadata.get("agent_name", "agent")
298
+
299
+ # Create message dictionary
300
+ message = {
301
+ "id": bubble.get("id", str(uuid.uuid4())),
302
+ "session_id": session_id,
303
+ "message": bubble.get("text", ""),
304
+ "sender_type": sender_type,
305
+ "sender_name": sender_name,
306
+ "message_type": "text",
307
+ "created_time": task.created_time
308
+ }
309
+ messages.append(message)
310
+
311
+ return messages
245
312
 
246
313
  def _is_valid_session_id(self, session_id: SessionId) -> bool:
247
314
  return (
@@ -289,4 +356,4 @@ class SessionService:
289
356
  "Failed to publish session deletion event to agent %s: %s",
290
357
  agent_id,
291
358
  e,
292
- )
359
+ )