solace-agent-mesh 1.0.9__py3-none-any.whl → 1.3.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 (220) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +182 -42
  2. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +171 -0
  3. solace_agent_mesh/agent/adk/callbacks.py +165 -104
  4. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +0 -18
  5. solace_agent_mesh/agent/adk/models/models_llm.txt +104 -55
  6. solace_agent_mesh/agent/adk/runner.py +25 -17
  7. solace_agent_mesh/agent/adk/services.py +3 -3
  8. solace_agent_mesh/agent/adk/setup.py +11 -0
  9. solace_agent_mesh/agent/adk/stream_parser.py +8 -1
  10. solace_agent_mesh/agent/adk/tool_wrapper.py +10 -3
  11. solace_agent_mesh/agent/agent_llm.txt +355 -18
  12. solace_agent_mesh/agent/protocol/event_handlers.py +460 -317
  13. solace_agent_mesh/agent/protocol/protocol_llm.txt +54 -7
  14. solace_agent_mesh/agent/sac/app.py +2 -2
  15. solace_agent_mesh/agent/sac/component.py +211 -517
  16. solace_agent_mesh/agent/sac/sac_llm.txt +133 -63
  17. solace_agent_mesh/agent/testing/testing_llm.txt +25 -58
  18. solace_agent_mesh/agent/tools/peer_agent_tool.py +15 -11
  19. solace_agent_mesh/agent/tools/tools_llm.txt +234 -69
  20. solace_agent_mesh/agent/utils/artifact_helpers.py +35 -1
  21. solace_agent_mesh/agent/utils/utils_llm.txt +90 -105
  22. solace_agent_mesh/assets/docs/404.html +3 -3
  23. solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/{75384d09.ccd480c4.js → 75384d09.bf78fbdb.js} +1 -1
  25. solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/main.08d30374.js +2 -0
  28. solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +1 -0
  29. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +4 -4
  30. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
  31. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
  32. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
  33. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
  34. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
  35. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
  37. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
  38. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
  39. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +105 -0
  44. solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +53 -0
  45. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
  53. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
  56. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +4 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  64. solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
  65. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  66. solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
  67. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  68. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  69. solace_agent_mesh/cli/__init__.py +1 -1
  70. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
  71. solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
  72. solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
  73. solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
  74. solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
  75. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
  76. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
  77. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
  78. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
  79. solace_agent_mesh/cli/commands/run_cmd.py +5 -3
  80. solace_agent_mesh/cli/utils.py +68 -12
  81. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
  82. solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
  83. solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
  84. solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
  85. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
  86. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
  87. solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
  88. solace_agent_mesh/common/a2a/__init__.py +213 -0
  89. solace_agent_mesh/common/a2a/a2a_llm.txt +182 -0
  90. solace_agent_mesh/common/a2a/artifact.py +328 -0
  91. solace_agent_mesh/common/a2a/events.py +183 -0
  92. solace_agent_mesh/common/a2a/message.py +307 -0
  93. solace_agent_mesh/common/a2a/protocol.py +513 -0
  94. solace_agent_mesh/common/a2a/task.py +127 -0
  95. solace_agent_mesh/common/a2a/translation.py +653 -0
  96. solace_agent_mesh/common/a2a/types.py +54 -0
  97. solace_agent_mesh/common/a2a_spec/a2a.json +2576 -0
  98. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +407 -0
  99. solace_agent_mesh/common/a2a_spec/schemas/agent_progress_update.json +18 -0
  100. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +31 -0
  101. solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +18 -0
  102. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +235 -0
  103. solace_agent_mesh/common/a2a_spec/schemas/tool_invocation_start.json +26 -0
  104. solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +25 -0
  105. solace_agent_mesh/common/agent_registry.py +1 -1
  106. solace_agent_mesh/common/common_llm.txt +192 -70
  107. solace_agent_mesh/common/data_parts.py +99 -0
  108. solace_agent_mesh/common/middleware/middleware_llm.txt +17 -17
  109. solace_agent_mesh/common/sac/__init__.py +0 -0
  110. solace_agent_mesh/common/sac/sac_llm.txt +71 -0
  111. solace_agent_mesh/common/sac/sam_component_base.py +252 -0
  112. solace_agent_mesh/common/services/providers/providers_llm.txt +51 -84
  113. solace_agent_mesh/common/services/services_llm.txt +206 -26
  114. solace_agent_mesh/common/utils/artifact_utils.py +29 -0
  115. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +176 -80
  116. solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
  117. solace_agent_mesh/common/utils/utils_llm.txt +323 -42
  118. solace_agent_mesh/config_portal/backend/common.py +2 -2
  119. solace_agent_mesh/config_portal/backend/plugin_catalog/constants.py +1 -1
  120. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
  121. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
  122. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  123. solace_agent_mesh/core_a2a/core_a2a_llm.txt +10 -8
  124. solace_agent_mesh/core_a2a/service.py +20 -44
  125. solace_agent_mesh/evaluation/message_organizer.py +35 -56
  126. solace_agent_mesh/evaluation/run.py +26 -5
  127. solace_agent_mesh/evaluation/subscriber.py +35 -10
  128. solace_agent_mesh/evaluation/summary_builder.py +27 -34
  129. solace_agent_mesh/gateway/base/app.py +27 -1
  130. solace_agent_mesh/gateway/base/base_llm.txt +177 -72
  131. solace_agent_mesh/gateway/base/component.py +294 -523
  132. solace_agent_mesh/gateway/gateway_llm.txt +299 -58
  133. solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
  134. solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
  135. solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
  136. solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
  137. solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
  138. solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
  139. solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
  140. solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
  141. solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
  142. solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
  143. solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
  144. solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
  145. solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
  146. solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
  147. solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
  148. solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
  149. solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
  150. solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
  151. solace_agent_mesh/gateway/http_sse/app.py +31 -1
  152. solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
  153. solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
  154. solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
  155. solace_agent_mesh/gateway/http_sse/component.py +371 -236
  156. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +29 -29
  157. solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
  158. solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
  159. solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
  160. solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
  161. solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
  162. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +272 -36
  163. solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
  164. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
  165. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
  166. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
  167. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
  168. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
  169. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
  170. solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
  171. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
  172. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
  173. solace_agent_mesh/gateway/http_sse/main.py +293 -91
  174. solace_agent_mesh/gateway/http_sse/routers/agents.py +1 -1
  175. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +137 -56
  176. solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
  177. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +231 -5
  178. solace_agent_mesh/gateway/http_sse/routers/tasks.py +199 -171
  179. solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
  180. solace_agent_mesh/gateway/http_sse/services/agent_service.py +1 -1
  181. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +89 -135
  182. solace_agent_mesh/gateway/http_sse/services/task_service.py +2 -5
  183. solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
  184. solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
  185. solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
  186. solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
  187. solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
  188. solace_agent_mesh/solace_agent_mesh_llm.txt +362 -0
  189. solace_agent_mesh/templates/gateway_component_template.py +149 -98
  190. solace_agent_mesh/templates/shared_config.yaml +4 -5
  191. solace_agent_mesh/templates/webui.yaml +8 -10
  192. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +9 -6
  193. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +197 -141
  194. solace_agent_mesh/assets/docs/assets/js/f284c35a.731836ad.js +0 -1
  195. solace_agent_mesh/assets/docs/assets/js/main.3d0e7879.js +0 -2
  196. solace_agent_mesh/assets/docs/assets/js/runtime~main.05d19492.js +0 -1
  197. solace_agent_mesh/assets/docs/lunr-index-1757091012487.json +0 -1
  198. solace_agent_mesh/assets/docs/search-doc-1757091012487.json +0 -1
  199. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
  200. solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
  201. solace_agent_mesh/client/webui/frontend/static/assets/main-D0FnP_W4.css +0 -1
  202. solace_agent_mesh/client/webui/frontend/static/assets/main-Do32sFPX.js +0 -708
  203. solace_agent_mesh/common/a2a_protocol.py +0 -564
  204. solace_agent_mesh/common/client/__init__.py +0 -4
  205. solace_agent_mesh/common/client/card_resolver.py +0 -21
  206. solace_agent_mesh/common/client/client.py +0 -85
  207. solace_agent_mesh/common/client/client_llm.txt +0 -133
  208. solace_agent_mesh/common/server/__init__.py +0 -4
  209. solace_agent_mesh/common/server/server.py +0 -122
  210. solace_agent_mesh/common/server/server_llm.txt +0 -169
  211. solace_agent_mesh/common/server/task_manager.py +0 -291
  212. solace_agent_mesh/common/server/utils.py +0 -28
  213. solace_agent_mesh/common/types.py +0 -411
  214. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
  215. solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -80
  216. solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
  217. /solace_agent_mesh/assets/docs/assets/js/{main.3d0e7879.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
  218. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
  219. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
  220. {solace_agent_mesh-1.0.9.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,65 +1,65 @@
1
+ # DEVELOPER GUIDE: components
2
+
1
3
  ## Quick Summary
2
4
  This directory contains components for the HTTP SSE (Server-Sent Events) gateway, designed to work within the Solace AI Connector (SAC) framework. The primary component forwards messages received from the Solace broker to an internal queue, enabling real-time visualization in a web-based user interface.
3
5
 
4
6
  ## Files Overview
5
- - `__init__.py`: Makes the `VisualizationForwarderComponent` class directly importable from the `components` package.
6
- - `visualization_forwarder_component.py`: Defines a component that forwards messages from a broker input to a Python `queue.Queue` for visualization.
7
+ - `__init__.py` - Makes the `VisualizationForwarderComponent` class directly importable from the `components` package
8
+ - `visualization_forwarder_component.py` - Defines a SAC component that forwards messages from a broker input to a Python `queue.Queue` for visualization
7
9
 
8
10
  ## Developer API Reference
9
11
 
10
12
  ### __init__.py
11
- **Purpose:** Exposes the public components of this directory for easy importing.
12
- **Import:** `from gateway.http_sse.components import VisualizationForwarderComponent`
13
+ **Purpose:** Exposes the public components of this directory for easy importing
14
+ **Import:** `from solace_agent_mesh.gateway.http_sse.components import VisualizationForwarderComponent`
13
15
 
14
16
  **Exports:**
15
- - `VisualizationForwarderComponent`: The main component class for forwarding messages to a visualization queue.
16
-
17
- ---
17
+ - `VisualizationForwarderComponent` - The main component class for forwarding messages to a visualization queue
18
18
 
19
19
  ### visualization_forwarder_component.py
20
- **Purpose:** A Solace AI Connector (SAC) component that listens for messages from a `BrokerInput` and forwards them to a specified Python `queue.Queue`. This is primarily used to send data to the Web UI for real-time display.
21
- **Import:** `from gateway.http_sse.components.visualization_forwarder_component import VisualizationForwarderComponent`
20
+ **Purpose:** A Solace AI Connector (SAC) component that listens for messages from a `BrokerInput` and forwards them to a specified Python `queue.Queue` for real-time visualization
21
+ **Import:** `from solace_agent_mesh.gateway.http_sse.components.visualization_forwarder_component import VisualizationForwarderComponent`
22
22
 
23
23
  **Classes:**
24
- - `VisualizationForwarderComponent(**kwargs: Any)` - A component that forwards messages to a target queue. It is initialized with configuration parameters, most importantly `target_queue_ref`.
25
- - `invoke(self, message: SolaceMessage, data: Dict[str, Any]) -> None` - The core method called by the SAC framework for each incoming message. It formats the data and places it onto the target queue. This method should not be called directly by developers; the framework handles its execution.
24
+ - `VisualizationForwarderComponent(**kwargs: Any)` - A component that forwards messages to a target queue, initialized with configuration parameters including `target_queue_ref`
25
+ - `invoke(message: SolaceMessage, data: Dict[str, Any]) -> None` - Core method called by SAC framework for each incoming message; formats data and places it onto the target queue
26
+ - `target_queue: queue.Queue` - The queue instance where messages are forwarded
26
27
 
27
28
  **Constants/Variables:**
28
- - `info: Dict` - A metadata dictionary required by the SAC framework. It describes the component's configuration parameters, input schema, and purpose. This is for framework use and not for direct interaction.
29
+ - `info: Dict` - Metadata dictionary required by SAC framework describing component configuration, input schema, and purpose
29
30
 
30
31
  **Usage Examples:**
31
32
  ```python
32
33
  import queue
33
- from gateway.http_sse.components import VisualizationForwarderComponent
34
+ from solace_agent_mesh.gateway.http_sse.components import VisualizationForwarderComponent
34
35
  from solace_ai_connector.common.message import Message as SolaceMessage
35
36
 
36
- # 1. Create a target queue that will receive the forwarded messages.
37
- # This queue is typically managed by another component, like a Web UI backend.
37
+ # 1. Create a target queue that will receive the forwarded messages
38
38
  visualization_queue = queue.Queue()
39
39
 
40
- # 2. Instantiate the component, providing a reference to the target queue.
41
- # This is usually done within a SAC flow configuration file.
40
+ # 2. Instantiate the component with target queue reference
42
41
  forwarder = VisualizationForwarderComponent(
43
42
  name="my_forwarder",
44
43
  target_queue_ref=visualization_queue
45
44
  )
46
45
 
47
- # 3. The `invoke` method is called automatically by the SAC framework when a message
48
- # arrives from a connected BrokerInput component.
46
+ # 3. The invoke method is called automatically by SAC framework
47
+ # when messages arrive from connected BrokerInput component
49
48
 
50
- # Example of what the consuming component would get from the queue:
51
- # A dictionary containing the message topic, payload, and other details.
52
- #
53
- # if not visualization_queue.empty():
54
- # forwarded_data = visualization_queue.get()
55
- # print(f"Received topic: {forwarded_data['topic']}")
56
- # print(f"Received payload: {forwarded_data['payload']}")
57
- #
58
- # Expected structure of `forwarded_data`:
49
+ # 4. Consume forwarded messages from the queue
50
+ if not visualization_queue.empty():
51
+ forwarded_data = visualization_queue.get()
52
+ print(f"Topic: {forwarded_data['topic']}")
53
+ print(f"Payload: {forwarded_data['payload']}")
54
+ print(f"User Properties: {forwarded_data['user_properties']}")
55
+
56
+ # Expected structure of forwarded_data:
59
57
  # {
60
58
  # "topic": "some/broker/topic",
61
59
  # "payload": {"key": "value"},
62
60
  # "user_properties": {"prop1": "value1"},
63
61
  # "_original_broker_message": <SolaceMessage object>
64
62
  # }
65
- ```
63
+ ```
64
+
65
+ # content_hash: cee7f7b4ea7e87ab3f94f7e24d463f22fa045e50d54991c61b84fe95e8a7f77d
@@ -3,39 +3,40 @@ Defines FastAPI dependency injectors to access shared resources
3
3
  managed by the WebUIBackendComponent.
4
4
  """
5
5
 
6
- from fastapi import Depends, HTTPException, status, Request
7
- from typing import (
8
- TYPE_CHECKING,
9
- Callable,
10
- Dict,
11
- Optional,
12
- Any,
13
- )
14
- import os
6
+ from collections.abc import Callable
7
+ from typing import TYPE_CHECKING, Any
15
8
 
9
+ from fastapi import Depends, HTTPException, Request, status
16
10
  from solace_ai_connector.common.log import log
17
- from ...gateway.http_sse.sse_manager import SSEManager
18
- from ...gateway.http_sse.session_manager import SessionManager
19
- from ...common.agent_registry import AgentRegistry
20
11
 
12
+ from ...common.agent_registry import AgentRegistry
13
+ from ...common.middleware.config_resolver import ConfigResolver
14
+ from ...common.services.identity_service import BaseIdentityService
15
+ from ...core_a2a.service import CoreA2AService
16
+ from ...gateway.base.task_context import TaskContextManager
21
17
  from ...gateway.http_sse.services.agent_service import AgentService
22
- from ...gateway.http_sse.services.task_service import TaskService
23
18
  from ...gateway.http_sse.services.people_service import PeopleService
24
- from ...gateway.base.task_context import TaskContextManager
25
-
26
- from ...core_a2a.service import CoreA2AService
27
- from ...common.services.identity_service import BaseIdentityService
28
- from ...common.middleware.config_resolver import ConfigResolver
19
+ from ...gateway.http_sse.services.task_service import TaskService
20
+ from ...gateway.http_sse.session_manager import SessionManager
21
+ from ...gateway.http_sse.sse_manager import SSEManager
22
+ from .application.services.session_service import SessionService
23
+ from .infrastructure.persistence_service import PersistenceService
29
24
 
30
- from google.adk.artifacts import BaseArtifactService
25
+ try:
26
+ from google.adk.artifacts import BaseArtifactService
27
+ except ImportError:
28
+ # Mock BaseArtifactService for environments without Google ADK
29
+ class BaseArtifactService:
30
+ pass
31
31
 
32
32
 
33
33
  if TYPE_CHECKING:
34
34
  from gateway.http_sse.component import WebUIBackendComponent
35
35
 
36
36
  sac_component_instance: "WebUIBackendComponent" = None
37
+ persistence_service_instance: "PersistenceService" = None
37
38
 
38
- api_config: Optional[Dict[str, Any]] = None
39
+ api_config: dict[str, Any] | None = None
39
40
 
40
41
 
41
42
  def set_component_instance(component: "WebUIBackendComponent"):
@@ -48,7 +49,30 @@ def set_component_instance(component: "WebUIBackendComponent"):
48
49
  log.warning("[Dependencies] SAC Component instance already set.")
49
50
 
50
51
 
51
- def set_api_config(config: Dict[str, Any]):
52
+ def set_persistence_service(persistence_service: "PersistenceService"):
53
+ """Called by the component during its startup to provide its instance."""
54
+ global persistence_service_instance
55
+ if persistence_service_instance is None:
56
+ persistence_service_instance = persistence_service
57
+ log.info("[Dependencies] Persistence Service instance provided.")
58
+ else:
59
+ log.warning("[Dependencies] Persistence Service instance already set.")
60
+
61
+
62
+ def get_persistence_service() -> "PersistenceService":
63
+ """FastAPI dependency to get the PersistenceService instance."""
64
+ if persistence_service_instance is None:
65
+ log.warning(
66
+ "[Dependencies] PersistenceService not available - running in compatibility mode"
67
+ )
68
+ raise HTTPException(
69
+ status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
70
+ detail="Persistence service not available in compatibility mode.",
71
+ )
72
+ return persistence_service_instance
73
+
74
+
75
+ def set_api_config(config: dict[str, Any]):
52
76
  """Called during startup to provide API configuration."""
53
77
  global api_config
54
78
  if api_config is None:
@@ -71,7 +95,7 @@ def get_sac_component() -> "WebUIBackendComponent":
71
95
  return sac_component_instance
72
96
 
73
97
 
74
- def get_api_config() -> Dict[str, Any]:
98
+ def get_api_config() -> dict[str, Any]:
75
99
  """FastAPI dependency to get the API configuration."""
76
100
  if api_config is None:
77
101
  log.critical("[Dependencies] API configuration accessed before it was set!")
@@ -128,26 +152,43 @@ def get_user_id(
128
152
  ) -> str:
129
153
  """
130
154
  FastAPI dependency that returns the user's identity.
131
- It prioritizes the authenticated user from `request.state.user` (set by AuthMiddleware)
132
- and falls back to the SessionManager for non-authenticated or legacy scenarios.
155
+ When FRONTEND_USE_AUTHORIZATION is true: Fully relies on OAuth - user must be authenticated by AuthMiddleware.
156
+ When FRONTEND_USE_AUTHORIZATION is false: Uses development fallback user.
133
157
  """
134
158
  log.debug("[Dependencies] Resolving user_id string")
135
159
 
160
+ # AuthMiddleware should always set user state for both auth enabled/disabled cases
136
161
  if hasattr(request.state, "user") and request.state.user:
137
162
  user_id = request.state.user.get("id")
138
163
  if user_id:
139
164
  log.debug(f"[Dependencies] Using user ID from AuthMiddleware: {user_id}")
140
165
  return user_id
141
166
  else:
142
- log.warning(
143
- "[Dependencies] request.state.user exists but has no 'id' field. Falling back."
167
+ log.error(
168
+ "[Dependencies] request.state.user exists but has no 'id' field: %s. This indicates a bug in AuthMiddleware.",
169
+ request.state.user,
144
170
  )
145
171
 
146
- log.debug("[Dependencies] Falling back to SessionManager for user_id")
147
- try:
148
- return session_manager.get_a2a_client_id(request)
149
- except AssertionError:
150
- return f"anonymous_user:{os.urandom(8).hex()}"
172
+ # If we reach here, AuthMiddleware didn't set user state properly
173
+ use_authorization = session_manager.use_authorization
174
+
175
+ if use_authorization:
176
+ # When OAuth is enabled, we should never reach here - AuthMiddleware should have handled authentication
177
+ log.error(
178
+ "[Dependencies] OAuth is enabled but no authenticated user found. This indicates an authentication failure or middleware bug."
179
+ )
180
+ raise HTTPException(
181
+ status_code=status.HTTP_401_UNAUTHORIZED,
182
+ detail="Authentication required but user not found",
183
+ )
184
+ else:
185
+ # When auth is disabled, use development fallback user
186
+ fallback_id = "sam_dev_user"
187
+ log.info(
188
+ "[Dependencies] Authorization disabled and no user in request state, using fallback user: %s",
189
+ fallback_id,
190
+ )
191
+ return fallback_id
151
192
 
152
193
 
153
194
  def ensure_session_id(
@@ -161,21 +202,21 @@ def ensure_session_id(
161
202
 
162
203
  def get_identity_service(
163
204
  component: "WebUIBackendComponent" = Depends(get_sac_component),
164
- ) -> Optional[BaseIdentityService]:
205
+ ) -> BaseIdentityService | None:
165
206
  """FastAPI dependency to get the configured IdentityService instance."""
166
207
  log.debug("[Dependencies] get_identity_service called")
167
208
  return component.identity_service
168
209
 
169
210
 
170
211
  def get_people_service(
171
- identity_service: Optional[BaseIdentityService] = Depends(get_identity_service),
212
+ identity_service: BaseIdentityService | None = Depends(get_identity_service),
172
213
  ) -> PeopleService:
173
214
  """FastAPI dependency to get an instance of PeopleService."""
174
215
  log.debug("[Dependencies] get_people_service called")
175
216
  return PeopleService(identity_service=identity_service)
176
217
 
177
218
 
178
- PublishFunc = Callable[[str, Dict, Optional[Dict]], None]
219
+ PublishFunc = Callable[[str, dict, dict | None], None]
179
220
 
180
221
 
181
222
  def get_publish_a2a_func(
@@ -212,7 +253,7 @@ def get_config_resolver(
212
253
 
213
254
  def get_app_config(
214
255
  component: "WebUIBackendComponent" = Depends(get_sac_component),
215
- ) -> Dict[str, Any]:
256
+ ) -> dict[str, Any]:
216
257
  """
217
258
  FastAPI dependency to safely get the application configuration dictionary.
218
259
  """
@@ -225,8 +266,8 @@ async def get_user_config(
225
266
  user_id: str = Depends(get_user_id),
226
267
  config_resolver: ConfigResolver = Depends(get_config_resolver),
227
268
  component: "WebUIBackendComponent" = Depends(get_sac_component),
228
- app_config: Dict[str, Any] = Depends(get_app_config),
229
- ) -> Dict[str, Any]:
269
+ app_config: dict[str, Any] = Depends(get_app_config),
270
+ ) -> dict[str, Any]:
230
271
  """
231
272
  FastAPI dependency to get the user-specific configuration.
232
273
  """
@@ -243,7 +284,7 @@ async def get_user_config(
243
284
 
244
285
  def get_shared_artifact_service(
245
286
  component: "WebUIBackendComponent" = Depends(get_sac_component),
246
- ) -> Optional[BaseArtifactService]:
287
+ ) -> BaseArtifactService | None:
247
288
  """FastAPI dependency to get the shared ArtifactService."""
248
289
  log.debug("[Dependencies] get_shared_artifact_service called")
249
290
  return component.get_shared_artifact_service()
@@ -251,7 +292,7 @@ def get_shared_artifact_service(
251
292
 
252
293
  def get_embed_config(
253
294
  component: "WebUIBackendComponent" = Depends(get_sac_component),
254
- ) -> Dict[str, Any]:
295
+ ) -> dict[str, Any]:
255
296
  """FastAPI dependency to get embed-related configuration."""
256
297
  log.debug("[Dependencies] get_embed_config called")
257
298
  return component.get_embed_config()
@@ -314,3 +355,65 @@ def get_task_service(
314
355
  task_context_lock=task_context_manager._lock,
315
356
  app_name=app_name,
316
357
  )
358
+
359
+
360
+ def get_session_service(
361
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
362
+ ) -> SessionService:
363
+ log.debug("[Dependencies] get_session_service called")
364
+
365
+ if (
366
+ hasattr(component, "persistence_service")
367
+ and component.persistence_service is not None
368
+ ):
369
+ log.debug("Using database-backed session service")
370
+ container = component.persistence_service.container
371
+ return container.get_session_service()
372
+ else:
373
+ log.debug("No database configured - session persistence not available")
374
+ raise HTTPException(
375
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
376
+ detail="Session management requires database configuration. Configure 'database_url' in your gateway configuration.",
377
+ )
378
+
379
+
380
+ def get_session_validator(
381
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
382
+ ) -> Callable[[str, str], bool]:
383
+ """
384
+ FastAPI dependency that returns a session validator function.
385
+
386
+ With database: Validates sessions against database
387
+ Without database: Validates sessions using basic checks (session exists in recent activity)
388
+ """
389
+ log.debug("[Dependencies] get_session_validator called")
390
+
391
+ # Check if component has a persistence service (database-backed)
392
+ if (
393
+ hasattr(component, "persistence_service")
394
+ and component.persistence_service is not None
395
+ ):
396
+ log.debug("Using database-backed session validation")
397
+
398
+ def validate_with_database(session_id: str, user_id: str) -> bool:
399
+ container = component.persistence_service.container
400
+ session_service = container.get_session_service()
401
+ session_domain = session_service.get_session(
402
+ session_id=session_id, user_id=user_id
403
+ )
404
+ return session_domain is not None
405
+
406
+ return validate_with_database
407
+ else:
408
+ log.debug("No database configured - using basic session validation")
409
+
410
+ def validate_without_database(session_id: str, user_id: str) -> bool:
411
+ """Basic validation: check session ID format and user authentication"""
412
+ # Validate session ID format (should be web-session-* format from SessionManager)
413
+ if not session_id or not session_id.startswith("web-session-"):
414
+ return False
415
+ # If user_id is provided (authenticated), allow access
416
+ # This provides basic security while allowing filesystem-based artifacts
417
+ return bool(user_id)
418
+
419
+ return validate_without_database
@@ -0,0 +1,3 @@
1
+ from .session import Message, Session, SessionHistory
2
+
3
+ __all__ = ["Session", "Message", "SessionHistory"]
@@ -0,0 +1,90 @@
1
+ from datetime import datetime, timezone
2
+
3
+ from pydantic import BaseModel
4
+
5
+ from ...shared.enums import MessageType, SenderType, SessionStatus
6
+ from ...shared.types import AgentId, MessageId, SessionId, UserId
7
+
8
+
9
+ class Session(BaseModel):
10
+ id: SessionId
11
+ user_id: UserId
12
+ name: str | None = None
13
+ agent_id: AgentId | None = None
14
+ status: SessionStatus = SessionStatus.ACTIVE
15
+ created_at: datetime
16
+ updated_at: datetime | None = None
17
+ last_activity: datetime | None = None
18
+
19
+ def update_name(self, new_name: str) -> None:
20
+ if not new_name or len(new_name.strip()) == 0:
21
+ raise ValueError("Session name cannot be empty")
22
+ if len(new_name) > 255:
23
+ raise ValueError("Session name cannot exceed 255 characters")
24
+
25
+ self.name = new_name.strip()
26
+ self.updated_at = datetime.now(timezone.utc)
27
+
28
+ def mark_activity(self) -> None:
29
+ self.last_activity = datetime.now(timezone.utc)
30
+ self.updated_at = datetime.now(timezone.utc)
31
+
32
+ def archive(self) -> None:
33
+ self.status = SessionStatus.ARCHIVED
34
+ self.updated_at = datetime.now(timezone.utc)
35
+
36
+ def activate(self) -> None:
37
+ self.status = SessionStatus.ACTIVE
38
+ self.updated_at = datetime.now(timezone.utc)
39
+
40
+ def can_be_deleted_by_user(self, user_id: UserId) -> bool:
41
+ return self.user_id == user_id
42
+
43
+ def can_be_accessed_by_user(self, user_id: UserId) -> bool:
44
+ return self.user_id == user_id
45
+
46
+
47
+ class Message(BaseModel):
48
+ id: MessageId
49
+ session_id: SessionId
50
+ message: str
51
+ sender_type: SenderType
52
+ sender_name: str
53
+ message_type: MessageType = MessageType.TEXT
54
+ created_at: datetime
55
+
56
+ def validate_message_content(self) -> None:
57
+ if not self.message or len(self.message.strip()) == 0:
58
+ raise ValueError("Message content cannot be empty")
59
+ if len(self.message) > 10_000_000:
60
+ raise ValueError("Message content exceeds maximum length (10MB)")
61
+
62
+ def is_from_user(self) -> bool:
63
+ return self.sender_type == SenderType.USER
64
+
65
+ def is_from_agent(self) -> bool:
66
+ return self.sender_type == SenderType.AGENT
67
+
68
+ def is_system_message(self) -> bool:
69
+ return self.sender_type == SenderType.SYSTEM
70
+
71
+
72
+ class SessionHistory(BaseModel):
73
+ session: Session
74
+ messages: list[Message] = []
75
+ total_message_count: int = 0
76
+
77
+ def add_message(self, message: Message) -> None:
78
+ if message.session_id != self.session.id:
79
+ raise ValueError("Message does not belong to this session")
80
+
81
+ message.validate_message_content()
82
+ self.messages.append(message)
83
+ self.total_message_count += 1
84
+ self.session.mark_activity()
85
+
86
+ def get_messages_by_sender_type(self, sender_type: SenderType) -> list[Message]:
87
+ return [msg for msg in self.messages if msg.sender_type == sender_type]
88
+
89
+ def get_latest_messages(self, count: int = 10) -> list[Message]:
90
+ return sorted(self.messages, key=lambda x: x.created_at, reverse=True)[:count]
@@ -0,0 +1,3 @@
1
+ from .session_repository import IMessageRepository, ISessionRepository
2
+
3
+ __all__ = ["ISessionRepository", "IMessageRepository"]
@@ -0,0 +1,54 @@
1
+ from abc import ABC, abstractmethod
2
+
3
+ from ...shared.types import PaginationInfo, SessionId, UserId
4
+ from ..entities.session import Message, Session
5
+
6
+
7
+ class ISessionRepository(ABC):
8
+ @abstractmethod
9
+ def get_by_id(self, session_id: SessionId) -> Session | None:
10
+ pass
11
+
12
+ @abstractmethod
13
+ def get_by_user_id(
14
+ self, user_id: UserId, pagination: PaginationInfo | None = None
15
+ ) -> list[Session]:
16
+ pass
17
+
18
+ @abstractmethod
19
+ def get_user_session(
20
+ self, session_id: SessionId, user_id: UserId
21
+ ) -> Session | None:
22
+ pass
23
+
24
+ @abstractmethod
25
+ def create(self, session: Session) -> Session:
26
+ pass
27
+
28
+ @abstractmethod
29
+ def update(self, session: Session) -> Session | None:
30
+ pass
31
+
32
+ @abstractmethod
33
+ def delete(self, session_id: SessionId, user_id: UserId) -> bool:
34
+ pass
35
+
36
+ @abstractmethod
37
+ def exists(self, session_id: SessionId) -> bool:
38
+ pass
39
+
40
+
41
+ class IMessageRepository(ABC):
42
+ @abstractmethod
43
+ def get_by_session_id(
44
+ self, session_id: SessionId, pagination: PaginationInfo | None = None
45
+ ) -> list[Message]:
46
+ pass
47
+
48
+ @abstractmethod
49
+ def create(self, message: Message) -> Message:
50
+ pass
51
+
52
+ @abstractmethod
53
+ def delete_by_session_id(self, session_id: SessionId) -> bool:
54
+ pass