solace-agent-mesh 1.5.1__py3-none-any.whl → 1.6.1__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 (184) hide show
  1. solace_agent_mesh/agent/adk/callbacks.py +0 -5
  2. solace_agent_mesh/agent/adk/models/lite_llm.py +123 -8
  3. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +245 -0
  4. solace_agent_mesh/agent/protocol/event_handlers.py +213 -31
  5. solace_agent_mesh/agent/proxies/__init__.py +0 -0
  6. solace_agent_mesh/agent/proxies/a2a/__init__.py +3 -0
  7. solace_agent_mesh/agent/proxies/a2a/app.py +55 -0
  8. solace_agent_mesh/agent/proxies/a2a/component.py +1115 -0
  9. solace_agent_mesh/agent/proxies/a2a/config.py +140 -0
  10. solace_agent_mesh/agent/proxies/a2a/oauth_token_cache.py +104 -0
  11. solace_agent_mesh/agent/proxies/base/__init__.py +3 -0
  12. solace_agent_mesh/agent/proxies/base/app.py +99 -0
  13. solace_agent_mesh/agent/proxies/base/component.py +650 -0
  14. solace_agent_mesh/agent/proxies/base/config.py +85 -0
  15. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +17 -0
  16. solace_agent_mesh/agent/sac/app.py +58 -5
  17. solace_agent_mesh/agent/sac/component.py +238 -75
  18. solace_agent_mesh/agent/sac/task_execution_context.py +46 -0
  19. solace_agent_mesh/agent/tools/audio_tools.py +125 -8
  20. solace_agent_mesh/agent/tools/web_tools.py +10 -5
  21. solace_agent_mesh/agent/utils/artifact_helpers.py +141 -3
  22. solace_agent_mesh/assets/docs/404.html +3 -3
  23. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +1 -0
  25. solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/77cf947d.48cb18a2.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +1 -0
  28. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
  29. solace_agent_mesh/assets/docs/assets/js/{ad71b5ed.60668e9e.js → ad71b5ed.af3ecfd1.js} +1 -1
  30. solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
  31. solace_agent_mesh/assets/docs/assets/js/{da0b5bad.9d369087.js → da0b5bad.d08a9466.js} +1 -1
  32. solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +1 -0
  34. solace_agent_mesh/assets/docs/assets/js/{e3d9abda.2b916f9e.js → e3d9abda.6b9493d0.js} +1 -1
  35. solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +1 -0
  36. solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +1 -0
  37. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +1 -0
  38. solace_agent_mesh/assets/docs/assets/js/{main.bd3c34f3.js → main.b12eac43.js} +2 -2
  39. solace_agent_mesh/assets/docs/assets/js/runtime~main.e268214e.js +1 -0
  40. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +15 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
  44. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +4 -4
  45. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +262 -0
  52. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +3 -3
  53. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +31 -3
  54. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +3 -3
  55. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +3 -3
  56. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +5 -5
  58. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +135 -0
  61. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +6 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
  64. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +4 -4
  65. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +5 -5
  66. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
  67. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
  68. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
  69. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
  70. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
  71. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
  72. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +3 -3
  73. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +3 -3
  74. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +3 -3
  75. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +3 -3
  76. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +3 -3
  77. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +3 -3
  78. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  79. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
  80. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +6 -5
  81. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +3 -3
  82. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +3 -3
  83. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +100 -3
  84. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +3 -3
  85. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
  86. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
  87. solace_agent_mesh/assets/docs/lunr-index-1761248203150.json +1 -0
  88. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  89. solace_agent_mesh/assets/docs/search-doc-1761248203150.json +1 -0
  90. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  91. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  92. solace_agent_mesh/cli/__init__.py +1 -1
  93. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +2 -69
  94. solace_agent_mesh/cli/commands/eval_cmd.py +11 -49
  95. solace_agent_mesh/cli/commands/init_cmd/__init__.py +0 -5
  96. solace_agent_mesh/cli/commands/init_cmd/env_step.py +10 -12
  97. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +9 -61
  98. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +9 -49
  99. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +1 -2
  100. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DwrxZE0E.js → authCallback-BTf6dqwp.js} +1 -1
  101. solace_agent_mesh/client/webui/frontend/static/assets/{client-DarGQzyw.js → client-CaY59VuC.js} +1 -1
  102. solace_agent_mesh/client/webui/frontend/static/assets/main-B32noGmR.js +342 -0
  103. solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +1 -0
  104. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BKIeiHj_.js → vendor-BEmvJSYz.js} +1 -1
  105. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  106. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  107. solace_agent_mesh/common/a2a/__init__.py +24 -0
  108. solace_agent_mesh/common/a2a/artifact.py +39 -0
  109. solace_agent_mesh/common/a2a/events.py +29 -0
  110. solace_agent_mesh/common/a2a/message.py +68 -0
  111. solace_agent_mesh/common/a2a/protocol.py +151 -1
  112. solace_agent_mesh/common/agent_registry.py +83 -3
  113. solace_agent_mesh/common/constants.py +3 -1
  114. solace_agent_mesh/common/sac/sam_component_base.py +383 -4
  115. solace_agent_mesh/common/utils/pydantic_utils.py +12 -0
  116. solace_agent_mesh/config_portal/backend/common.py +1 -1
  117. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +98 -0
  118. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-44d62be6.js → manifest-61038fc6.js} +1 -1
  119. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  120. solace_agent_mesh/evaluation/evaluator.py +128 -104
  121. solace_agent_mesh/evaluation/message_organizer.py +116 -110
  122. solace_agent_mesh/evaluation/report_data_processor.py +84 -86
  123. solace_agent_mesh/evaluation/report_generator.py +73 -79
  124. solace_agent_mesh/evaluation/run.py +421 -235
  125. solace_agent_mesh/evaluation/shared/__init__.py +92 -0
  126. solace_agent_mesh/evaluation/shared/constants.py +47 -0
  127. solace_agent_mesh/evaluation/shared/exceptions.py +50 -0
  128. solace_agent_mesh/evaluation/shared/helpers.py +35 -0
  129. solace_agent_mesh/evaluation/shared/test_case_loader.py +167 -0
  130. solace_agent_mesh/evaluation/shared/test_suite_loader.py +280 -0
  131. solace_agent_mesh/evaluation/subscriber.py +111 -232
  132. solace_agent_mesh/evaluation/summary_builder.py +227 -117
  133. solace_agent_mesh/gateway/base/app.py +16 -1
  134. solace_agent_mesh/gateway/base/component.py +112 -39
  135. solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
  136. solace_agent_mesh/gateway/http_sse/component.py +99 -3
  137. solace_agent_mesh/gateway/http_sse/dependencies.py +4 -4
  138. solace_agent_mesh/gateway/http_sse/main.py +1 -0
  139. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +12 -13
  140. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +15 -18
  141. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +25 -18
  142. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +30 -26
  143. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +35 -44
  144. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +4 -3
  145. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +95 -203
  146. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +4 -3
  147. solace_agent_mesh/gateway/http_sse/routers/sessions.py +2 -2
  148. solace_agent_mesh/gateway/http_sse/routers/tasks.py +33 -41
  149. solace_agent_mesh/gateway/http_sse/routers/users.py +47 -1
  150. solace_agent_mesh/gateway/http_sse/routers/visualization.py +17 -11
  151. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +4 -4
  152. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +51 -43
  153. solace_agent_mesh/gateway/http_sse/services/session_service.py +20 -20
  154. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +8 -8
  155. solace_agent_mesh/gateway/http_sse/shared/base_repository.py +45 -71
  156. solace_agent_mesh/gateway/http_sse/shared/types.py +0 -18
  157. solace_agent_mesh/templates/gateway_config_template.yaml +0 -5
  158. solace_agent_mesh/templates/logging_config_template.ini +10 -6
  159. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +0 -3
  160. solace_agent_mesh/templates/shared_config.yaml +40 -0
  161. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/METADATA +47 -21
  162. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/RECORD +166 -145
  163. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.e49689dd.js +0 -1
  164. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.39d5851d.js +0 -1
  165. solace_agent_mesh/assets/docs/assets/js/71da7b71.804d6567.js +0 -1
  166. solace_agent_mesh/assets/docs/assets/js/77cf947d.64c9bd6c.js +0 -1
  167. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.dd810042.js +0 -1
  168. solace_agent_mesh/assets/docs/assets/js/db924877.cbc66f02.js +0 -1
  169. solace_agent_mesh/assets/docs/assets/js/de915948.139b4b9c.js +0 -1
  170. solace_agent_mesh/assets/docs/assets/js/e6f9706b.582a78ca.js +0 -1
  171. solace_agent_mesh/assets/docs/assets/js/f284c35a.5766a13d.js +0 -1
  172. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.9c0297a6.js +0 -1
  173. solace_agent_mesh/assets/docs/assets/js/runtime~main.18dc45dd.js +0 -1
  174. solace_agent_mesh/assets/docs/lunr-index-1760121512891.json +0 -1
  175. solace_agent_mesh/assets/docs/search-doc-1760121512891.json +0 -1
  176. solace_agent_mesh/client/webui/frontend/static/assets/main-2nd1gbaH.js +0 -339
  177. solace_agent_mesh/client/webui/frontend/static/assets/main-DoKXctCM.css +0 -1
  178. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-BNuqpWDc.js +0 -98
  179. solace_agent_mesh/evaluation/config_loader.py +0 -657
  180. solace_agent_mesh/evaluation/test_case_loader.py +0 -714
  181. /solace_agent_mesh/assets/docs/assets/js/{main.bd3c34f3.js.LICENSE.txt → main.b12eac43.js.LICENSE.txt} +0 -0
  182. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/WHEEL +0 -0
  183. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/entry_points.txt +0 -0
  184. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.1.dist-info}/licenses/LICENSE +0 -0
@@ -6,7 +6,8 @@ import logging
6
6
  import abc
7
7
  import asyncio
8
8
  import threading
9
- from typing import Any
9
+ import functools
10
+ from typing import Any, Optional
10
11
 
11
12
  from solace_ai_connector.components.component_base import ComponentBase
12
13
 
@@ -15,6 +16,7 @@ from ..utils.message_utils import validate_message_size
15
16
 
16
17
  log = logging.getLogger(__name__)
17
18
 
19
+
18
20
  class SamComponentBase(ComponentBase, abc.ABC):
19
21
  """
20
22
  Abstract base class for high-level SAM components (Agents, Gateways).
@@ -54,8 +56,294 @@ class SamComponentBase(ComponentBase, abc.ABC):
54
56
 
55
57
  self._async_loop: asyncio.AbstractEventLoop | None = None
56
58
  self._async_thread: threading.Thread | None = None
59
+
60
+ # Timer callback registry
61
+ self._timer_callbacks: dict[str, Any] = {}
62
+ self._timer_callbacks_lock = threading.Lock()
63
+
64
+ # Trust Manager integration (enterprise feature) - initialized as part of _late_init
65
+ self.trust_manager: Optional[Any] = None
66
+
57
67
  log.info("%s SamComponentBase initialized successfully.", self.log_identifier)
58
68
 
69
+ def add_timer(
70
+ self,
71
+ delay_ms: int,
72
+ timer_id: str,
73
+ interval_ms: int = 0,
74
+ callback: Optional[Any] = None,
75
+ ):
76
+ """
77
+ Add a timer with optional callback.
78
+
79
+ Args:
80
+ delay_ms: Initial delay in milliseconds
81
+ timer_id: Unique timer identifier
82
+ interval_ms: Repeat interval in milliseconds (0 for one-shot)
83
+ callback: Optional callback function to invoke when timer fires.
84
+ If provided, callback will be invoked when timer event occurs.
85
+ Callback receives timer_data dict as argument.
86
+ Callback should be thread-safe or schedule work appropriately.
87
+ """
88
+ # Register callback if provided
89
+ if callback:
90
+ with self._timer_callbacks_lock:
91
+ if timer_id in self._timer_callbacks:
92
+ log.warning(
93
+ "%s Timer ID '%s' already has a registered callback. Overwriting.",
94
+ self.log_identifier,
95
+ timer_id,
96
+ )
97
+ self._timer_callbacks[timer_id] = callback
98
+ log.debug(
99
+ "%s Registered callback for timer: %s",
100
+ self.log_identifier,
101
+ timer_id,
102
+ )
103
+
104
+ # Call parent implementation to actually create the timer
105
+ super().add_timer(delay_ms=delay_ms, timer_id=timer_id, interval_ms=interval_ms)
106
+
107
+ def cancel_timer(self, timer_id: str):
108
+ """
109
+ Cancel a timer and remove its callback if registered.
110
+
111
+ Args:
112
+ timer_id: Timer identifier to cancel
113
+ """
114
+ # Remove callback registration
115
+ with self._timer_callbacks_lock:
116
+ if timer_id in self._timer_callbacks:
117
+ del self._timer_callbacks[timer_id]
118
+ log.debug(
119
+ "%s Unregistered callback for timer: %s",
120
+ self.log_identifier,
121
+ timer_id,
122
+ )
123
+
124
+ # Call parent implementation to actually cancel the timer
125
+ super().cancel_timer(timer_id)
126
+
127
+ def process_event(self, event):
128
+ """
129
+ Process incoming events by routing to appropriate handlers.
130
+
131
+ This base implementation handles MESSAGE and TIMER events:
132
+ - MESSAGE events are routed to _handle_message() abstract method
133
+ - TIMER events are routed to registered callbacks
134
+ - Other events are passed to parent class
135
+
136
+ Args:
137
+ event: Event object from SAC framework
138
+ """
139
+ from solace_ai_connector.common.event import Event, EventType
140
+ from solace_ai_connector.common.message import Message as SolaceMessage
141
+
142
+ if event.event_type == EventType.MESSAGE:
143
+ message: SolaceMessage = event.data
144
+ topic = message.get_topic()
145
+
146
+ if not topic:
147
+ log.warning(
148
+ "%s Received message without topic. Ignoring.",
149
+ self.log_identifier,
150
+ )
151
+ try:
152
+ message.call_negative_acknowledgements()
153
+ except Exception as nack_e:
154
+ log.error(
155
+ "%s Failed to NACK message without topic: %s",
156
+ self.log_identifier,
157
+ nack_e,
158
+ )
159
+ return
160
+
161
+ try:
162
+ # Delegate to abstract method implemented by subclass
163
+ self._handle_message(message, topic)
164
+ except Exception as e:
165
+ log.error(
166
+ "%s Error in _handle_message for topic %s: %s",
167
+ self.log_identifier,
168
+ topic,
169
+ e,
170
+ exc_info=True,
171
+ )
172
+ try:
173
+ message.call_negative_acknowledgements()
174
+ except Exception as nack_e:
175
+ log.error(
176
+ "%s Failed to NACK message after error: %s",
177
+ self.log_identifier,
178
+ nack_e,
179
+ )
180
+ self.handle_error(e, event)
181
+
182
+ elif event.event_type == EventType.TIMER:
183
+ # Handle timer events via callback registry
184
+ timer_data = event.data
185
+ timer_id = timer_data.get("timer_id")
186
+
187
+ if not timer_id:
188
+ log.warning(
189
+ "%s Timer event missing timer_id: %s",
190
+ self.log_identifier,
191
+ timer_data,
192
+ )
193
+ return
194
+
195
+ # Look up registered callback
196
+ with self._timer_callbacks_lock:
197
+ callback = self._timer_callbacks.get(timer_id)
198
+
199
+ if callback:
200
+ try:
201
+ log.debug(
202
+ "%s Invoking registered callback for timer: %s",
203
+ self.log_identifier,
204
+ timer_id,
205
+ )
206
+ callback(timer_data)
207
+ except Exception as e:
208
+ log.error(
209
+ "%s Error in timer callback for %s: %s",
210
+ self.log_identifier,
211
+ timer_id,
212
+ e,
213
+ exc_info=True,
214
+ )
215
+ else:
216
+ log.warning(
217
+ "%s No callback registered for timer: %s. Timer event ignored.",
218
+ self.log_identifier,
219
+ timer_id,
220
+ )
221
+ else:
222
+ # Pass other event types to parent class
223
+ super().process_event(event)
224
+
225
+ def _handle_message(self, message, topic: str) -> None:
226
+ """
227
+ Handle an incoming message by routing to async handler.
228
+
229
+ This base implementation schedules async processing on the component's
230
+ event loop. Subclasses can override this for custom sync handling,
231
+ or implement _handle_message_async() for async handling.
232
+
233
+ Args:
234
+ message: The Solace message (SolaceMessage instance)
235
+ topic: The topic the message was received on
236
+ """
237
+ loop = self.get_async_loop()
238
+ if loop and loop.is_running():
239
+ # Schedule async processing
240
+ coro = self._handle_message_async(message, topic)
241
+ future = asyncio.run_coroutine_threadsafe(coro, loop)
242
+ future.add_done_callback(
243
+ functools.partial(self._handle_async_message_completion, topic=topic)
244
+ )
245
+ else:
246
+ log.error(
247
+ "%s Async loop not available. Cannot process message on topic: %s",
248
+ self.log_identifier,
249
+ topic,
250
+ )
251
+ raise RuntimeError("Async loop not available for message processing")
252
+
253
+ def _handle_async_message_completion(self, future: asyncio.Future, topic: str):
254
+ """Callback to handle completion of async message processing."""
255
+ try:
256
+ if future.cancelled():
257
+ log.warning(
258
+ "%s Message processing for topic %s was cancelled.",
259
+ self.log_identifier,
260
+ topic,
261
+ )
262
+ elif future.done():
263
+ exception = future.exception()
264
+ if exception is not None:
265
+ log.error(
266
+ "%s Message processing for topic %s failed: %s",
267
+ self.log_identifier,
268
+ topic,
269
+ exception,
270
+ exc_info=exception,
271
+ )
272
+ else:
273
+ # Handle successful completion
274
+ try:
275
+ _ = future.result()
276
+ log.debug(
277
+ "%s Message processing for topic %s completed successfully.",
278
+ self.log_identifier,
279
+ topic,
280
+ )
281
+ # Optional: Process the result if needed
282
+ # self._process_successful_result(result, topic)
283
+ except Exception as result_exception:
284
+ # This catches exceptions that might occur when getting the result
285
+ log.error(
286
+ "%s Error retrieving result for topic %s: %s",
287
+ self.log_identifier,
288
+ topic,
289
+ result_exception,
290
+ exc_info=result_exception,
291
+ )
292
+ else:
293
+ # This case shouldn't normally occur in a completion callback,
294
+ # but it's good defensive programming
295
+ log.warning(
296
+ "%s Future for topic %s is not done in completion handler.",
297
+ self.log_identifier,
298
+ topic,
299
+ )
300
+ except Exception as e:
301
+ log.error(
302
+ "%s Error in async message completion handler for topic %s: %s",
303
+ self.log_identifier,
304
+ topic,
305
+ e,
306
+ exc_info=True,
307
+ )
308
+
309
+ @abc.abstractmethod
310
+ async def _handle_message_async(self, message, topic: str) -> None:
311
+ """
312
+ Async handler for incoming messages.
313
+
314
+ Subclasses must implement this to process messages asynchronously.
315
+ This runs on the component's dedicated async event loop.
316
+
317
+ Args:
318
+ message: The Solace message (SolaceMessage instance)
319
+ topic: The topic the message was received on
320
+ """
321
+ pass
322
+
323
+ def _late_init(self):
324
+ """Late initialization hook called after the component is fully set up."""
325
+
326
+ # Setup the Trust Manager if present (enterprise feature)
327
+ # NOTE: The Trust Manager should use component.get_broker_username() to retrieve
328
+ # the actual broker client-username for trust card topic construction. This is
329
+ # critical because trust cards MUST be published on topics that match the actual
330
+ # authentication identity (client-username) used to connect to the broker.
331
+ try:
332
+ from solace_agent_mesh_enterprise.common.trust import (
333
+ initialize_trust_manager,
334
+ )
335
+
336
+ trust_config = self.get_config("trust_manager")
337
+ if trust_config and trust_config.get("enabled", False):
338
+ self.trust_manager = initialize_trust_manager(self)
339
+ log.info("%s Enterprise Trust Manager initialized", self.log_identifier)
340
+ except ImportError:
341
+ log.debug("%s Enterprise Trust Manager not available", self.log_identifier)
342
+ except Exception as e:
343
+ log.error(
344
+ "%s Failed to initialize Trust Manager: %s", self.log_identifier, e
345
+ )
346
+
59
347
  def publish_a2a_message(
60
348
  self, payload: dict, topic: str, user_properties: dict | None = None
61
349
  ):
@@ -197,6 +485,10 @@ class SamComponentBase(ComponentBase, abc.ABC):
197
485
  def run(self):
198
486
  """Starts the component's dedicated async thread."""
199
487
  log.info("%s Starting SamComponentBase run method.", self.log_identifier)
488
+
489
+ # Do all initialization that needs to be done after we are fully setup
490
+ self._late_init()
491
+
200
492
  if not self._async_thread or not self._async_thread.is_alive():
201
493
  self._async_thread = threading.Thread(
202
494
  target=self._run_async_operations,
@@ -256,14 +548,101 @@ class SamComponentBase(ComponentBase, abc.ABC):
256
548
  """Returns the dedicated asyncio event loop for this component's async tasks."""
257
549
  return self._async_loop
258
550
 
551
+ def get_broker_username(self) -> Optional[str]:
552
+ """
553
+ Returns the broker username (client-username) that this component uses
554
+ to authenticate with the Solace broker.
555
+
556
+ This is critical for trust card publishing and verification, as the
557
+ trust card topic must match the actual authentication identity.
558
+
559
+ Returns:
560
+ The broker username if available, None otherwise.
561
+ """
562
+ try:
563
+ app = self.get_app()
564
+ if app and hasattr(app, "app_info"):
565
+ broker_config = app.app_info.get("broker", {})
566
+ broker_username = broker_config.get("broker_username")
567
+ if broker_username:
568
+ log.debug(
569
+ "%s Retrieved broker username: %s",
570
+ self.log_identifier,
571
+ broker_username,
572
+ )
573
+ return broker_username
574
+ else:
575
+ log.warning(
576
+ "%s Broker username not found in broker configuration",
577
+ self.log_identifier,
578
+ )
579
+ else:
580
+ log.warning(
581
+ "%s Unable to access app or app_info to retrieve broker username",
582
+ self.log_identifier,
583
+ )
584
+ except Exception as e:
585
+ log.error(
586
+ "%s Error retrieving broker username: %s",
587
+ self.log_identifier,
588
+ e,
589
+ exc_info=True,
590
+ )
591
+ return None
592
+
259
593
  @abc.abstractmethod
260
- async def _async_setup_and_run(self) -> None:
594
+ def _get_component_id(self) -> str:
595
+ """
596
+ Returns unique identifier for this component instance.
597
+ Must be implemented by subclasses.
598
+
599
+ Returns:
600
+ Unique component identifier (e.g., agent_name, gateway_id)
261
601
  """
262
- Abstract method for subclasses to implement their main asynchronous logic.
263
- This coroutine is executed within the managed event loop.
602
+ pass
603
+
604
+ @abc.abstractmethod
605
+ def _get_component_type(self) -> str:
606
+ """
607
+ Returns component type string.
608
+ Must be implemented by subclasses.
609
+
610
+ Returns:
611
+ Component type ("gateway", "agent", etc.)
264
612
  """
265
613
  pass
266
614
 
615
+ async def _async_setup_and_run(self) -> None:
616
+ """
617
+ Base async setup that initializes Trust Manager if present.
618
+ Subclasses should override and call super() first, then add their logic.
619
+ """
620
+ # Initialize Trust Manager if present (ENTERPRISE FEATURE)
621
+ if self.trust_manager:
622
+ try:
623
+ log.info(
624
+ "%s Initializing Trust Manager with periodic publishing...",
625
+ self.log_identifier,
626
+ )
627
+ # Pass event loop and add_timer method to Trust Manager
628
+ await self.trust_manager.initialize(
629
+ add_timer_callback=self.add_timer,
630
+ event_loop=self.get_async_loop(),
631
+ )
632
+ log.info(
633
+ "%s Trust Manager initialized successfully", self.log_identifier
634
+ )
635
+ except Exception as e:
636
+ log.error(
637
+ "%s Failed to initialize Trust Manager: %s",
638
+ self.log_identifier,
639
+ e,
640
+ exc_info=True,
641
+ )
642
+ # Trust Manager failure should not prevent component startup
643
+ # Set to None to disable trust manager for this session
644
+ self.trust_manager = None
645
+
267
646
  @abc.abstractmethod
268
647
  def _pre_async_cleanup(self) -> None:
269
648
  """
@@ -58,3 +58,15 @@ class SamConfigBase(BaseModel):
58
58
  def __iter__(self):
59
59
  """Provides dict-like iteration over keys."""
60
60
  return iter(self.model_dump())
61
+
62
+ def pop(self, key: str, default: Any = None) -> Any:
63
+ """
64
+ Provides dict-like .pop() method.
65
+ Removes the attribute and returns its value, or default if not present.
66
+ """
67
+ if hasattr(self, key):
68
+ value = getattr(self, key)
69
+ # Set to None rather than deleting, as Pydantic models don't support delattr
70
+ setattr(self, key, None)
71
+ return value
72
+ return default
@@ -34,7 +34,7 @@ AGENT_DEFAULTS = {
34
34
  "enable_embed_resolution": True,
35
35
  "enable_artifact_content_instruction": True,
36
36
  "tools": "[]",
37
- "session_service_type": USE_DEFAULT_SHARED_SESSION,
37
+ "session_service_type": "sql",
38
38
  "session_service_behavior": "PERSISTENT",
39
39
  "artifact_service_type": USE_DEFAULT_SHARED_ARTIFACT,
40
40
  "artifact_service_base_path": "/tmp/samv2",