solace-agent-mesh 1.4.12__py3-none-any.whl → 1.5.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agent/adk/adk_llm.txt +3 -4
- solace_agent_mesh/agent/adk/adk_llm_detail.txt +566 -0
- solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
- solace_agent_mesh/agent/adk/callbacks.py +51 -2
- solace_agent_mesh/agent/adk/models/lite_llm.py +1 -0
- solace_agent_mesh/agent/adk/models/models_llm.txt +1 -2
- solace_agent_mesh/agent/agent_llm.txt +1 -1
- solace_agent_mesh/agent/agent_llm_detail.txt +1702 -0
- solace_agent_mesh/agent/protocol/event_handlers.py +2 -13
- solace_agent_mesh/agent/protocol/protocol_llm.txt +15 -2
- solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +92 -0
- solace_agent_mesh/agent/sac/component.py +51 -21
- solace_agent_mesh/agent/sac/sac_llm.txt +15 -1
- solace_agent_mesh/agent/sac/sac_llm_detail.txt +200 -0
- solace_agent_mesh/agent/sac/task_execution_context.py +73 -0
- solace_agent_mesh/agent/testing/testing_llm_detail.txt +68 -0
- solace_agent_mesh/agent/tools/tools_llm.txt +148 -154
- solace_agent_mesh/agent/tools/tools_llm_detail.txt +274 -0
- solace_agent_mesh/agent/utils/utils_llm.txt +1 -1
- solace_agent_mesh/agent/utils/utils_llm_detail.txt +149 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/483cef9a.bf9398af.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js → main.0c149855.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/{runtime~main.40527046.js → runtime~main.c66557e4.js} +1 -1
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +8 -4
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/litellm_models/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +3 -3
- solace_agent_mesh/assets/docs/lunr-index-1760032255022.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1760032255022.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-j1LW-wlq.js → authCallback-DwrxZE0E.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/{client-B9p_nFNA.js → client-DarGQzyw.js} +1 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-CZbpmwfA.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C__uuUkB.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CS5YMf8a.js → vendor-BKIeiHj_.js} +80 -70
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
- solace_agent_mesh/common/a2a/a2a_llm.txt +1 -1
- solace_agent_mesh/common/a2a/a2a_llm_detail.txt +193 -0
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +1 -1
- solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +736 -0
- solace_agent_mesh/common/a2a_spec/schemas/llm_invocation.json +23 -0
- solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +93 -15
- solace_agent_mesh/common/a2a_spec/schemas/tool_result.json +23 -0
- solace_agent_mesh/common/common_llm.txt +24 -39
- solace_agent_mesh/common/common_llm_detail.txt +2562 -0
- solace_agent_mesh/common/data_parts.py +9 -1
- solace_agent_mesh/common/middleware/middleware_llm_detail.txt +185 -0
- solace_agent_mesh/common/sac/sac_llm.txt +1 -1
- solace_agent_mesh/common/sac/sac_llm_detail.txt +82 -0
- solace_agent_mesh/common/sam_events/sam_events_llm.txt +104 -0
- solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +115 -0
- solace_agent_mesh/common/services/services_llm.txt +57 -6
- solace_agent_mesh/common/services/services_llm_detail.txt +459 -0
- solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
- solace_agent_mesh/common/utils/utils_llm.txt +75 -87
- solace_agent_mesh/common/utils/utils_llm_detail.txt +572 -0
- solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +101 -0
- solace_agent_mesh/gateway/base/app.py +1 -1
- solace_agent_mesh/gateway/base/base_llm.txt +1 -1
- solace_agent_mesh/gateway/base/base_llm_detail.txt +235 -0
- solace_agent_mesh/gateway/gateway_llm.txt +242 -235
- solace_agent_mesh/gateway/gateway_llm_detail.txt +3885 -0
- solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +295 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +10 -1
- solace_agent_mesh/gateway/http_sse/alembic/versions/20251006_98882922fa59_add_tasks_events_feedback_chat_tasks.py +190 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +155 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +1 -1
- solace_agent_mesh/gateway/http_sse/app.py +148 -2
- solace_agent_mesh/gateway/http_sse/component.py +368 -60
- solace_agent_mesh/gateway/http_sse/components/components_llm.txt +46 -6
- solace_agent_mesh/gateway/http_sse/components/task_logger_forwarder.py +108 -0
- solace_agent_mesh/gateway/http_sse/components/visualization_forwarder_component.py +1 -1
- solace_agent_mesh/gateway/http_sse/dependencies.py +116 -26
- solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +172 -172
- solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +3278 -0
- solace_agent_mesh/gateway/http_sse/main.py +146 -41
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +3 -12
- solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +103 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +5 -3
- solace_agent_mesh/gateway/http_sse/repository/entities/chat_task.py +75 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +263 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/feedback.py +20 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +0 -16
- solace_agent_mesh/gateway/http_sse/repository/entities/task.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/task_event.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +81 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +73 -18
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -5
- solace_agent_mesh/gateway/http_sse/repository/models/chat_task_model.py +31 -0
- solace_agent_mesh/gateway/http_sse/repository/models/feedback_model.py +21 -0
- solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +266 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +3 -3
- solace_agent_mesh/gateway/http_sse/repository/models/task_event_model.py +25 -0
- solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +32 -0
- solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +340 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +4 -53
- solace_agent_mesh/gateway/http_sse/repository/task_repository.py +173 -0
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +1 -1
- solace_agent_mesh/gateway/http_sse/routers/config.py +26 -4
- solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +346 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +3 -3
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +83 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +2 -10
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/task_requests.py +58 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +5 -3
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +107 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +1 -15
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/task_responses.py +30 -0
- solace_agent_mesh/gateway/http_sse/routers/feedback.py +37 -0
- solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +255 -204
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +220 -40
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +168 -42
- solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +272 -0
- solace_agent_mesh/gateway/http_sse/services/feedback_service.py +241 -0
- solace_agent_mesh/gateway/http_sse/services/people_service.py +0 -80
- solace_agent_mesh/gateway/http_sse/services/services_llm.txt +177 -13
- solace_agent_mesh/gateway/http_sse/services/session_service.py +151 -84
- solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +317 -0
- solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +25 -14
- solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +285 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +7 -0
- solace_agent_mesh/gateway/http_sse/utils/__init__.py +1 -0
- solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +32 -0
- solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +47 -0
- solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
- solace_agent_mesh/solace_agent_mesh_llm_detail.txt +8599 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/RECORD +172 -124
- solace_agent_mesh/agent/adk/invocation_monitor.py +0 -295
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4736f2d8.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1759936913198.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1759936913198.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-ChRwcV89.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-DnnE01OM.js +0 -339
- solace_agent_mesh/gateway/http_sse/repository/entities/message.py +0 -41
- solace_agent_mesh/gateway/http_sse/repository/message_repository.py +0 -84
- solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +0 -45
- /solace_agent_mesh/assets/docs/assets/js/{main.f67fc9f4.js.LICENSE.txt → main.0c149855.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.4.12.dist-info → solace_agent_mesh-1.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -26,6 +26,10 @@ from ...gateway.http_sse.session_manager import SessionManager
|
|
|
26
26
|
from ...gateway.http_sse.sse_manager import SSEManager
|
|
27
27
|
from .sse_event_buffer import SSEEventBuffer
|
|
28
28
|
from .components import VisualizationForwarderComponent
|
|
29
|
+
from .components.task_logger_forwarder import TaskLoggerForwarderComponent
|
|
30
|
+
from .services.feedback_service import FeedbackService
|
|
31
|
+
from .services.task_logger_service import TaskLoggerService
|
|
32
|
+
from . import dependencies
|
|
29
33
|
|
|
30
34
|
try:
|
|
31
35
|
from google.adk.artifacts import BaseArtifactService
|
|
@@ -153,6 +157,23 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
153
157
|
else:
|
|
154
158
|
# Memory storage or no explicit configuration - no persistence service needed
|
|
155
159
|
self.database_url = None
|
|
160
|
+
|
|
161
|
+
# Validate that features requiring database persistence are not enabled
|
|
162
|
+
task_logging_config = self.get_config("task_logging", {})
|
|
163
|
+
if task_logging_config.get("enabled", False):
|
|
164
|
+
raise ValueError(
|
|
165
|
+
f"{self.log_identifier} Task logging requires SQL session storage. "
|
|
166
|
+
"Either set session_service.type='sql' with a valid database_url, "
|
|
167
|
+
"or disable task_logging.enabled."
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
feedback_config = self.get_config("feedback_publishing", {})
|
|
171
|
+
if feedback_config.get("enabled", False):
|
|
172
|
+
log.warning(
|
|
173
|
+
"%s Feedback publishing is enabled but database persistence is not configured. "
|
|
174
|
+
"Feedback will only be published to the broker, not stored locally.",
|
|
175
|
+
self.log_identifier
|
|
176
|
+
)
|
|
156
177
|
|
|
157
178
|
component_config = self.get_config("component_config", {})
|
|
158
179
|
app_config = component_config.get("app_config", {})
|
|
@@ -170,12 +191,18 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
170
191
|
self._visualization_internal_app: SACApp | None = None
|
|
171
192
|
self._visualization_broker_input: BrokerInput | None = None
|
|
172
193
|
self._visualization_message_queue: queue.Queue = queue.Queue(maxsize=200)
|
|
194
|
+
self._task_logger_queue: queue.Queue = queue.Queue(maxsize=200)
|
|
173
195
|
self._active_visualization_streams: dict[str, dict[str, Any]] = {}
|
|
174
196
|
self._visualization_locks: dict[asyncio.AbstractEventLoop, asyncio.Lock] = {}
|
|
175
197
|
self._visualization_locks_lock = threading.Lock()
|
|
176
198
|
self._global_visualization_subscriptions: dict[str, int] = {}
|
|
177
199
|
self._visualization_processor_task: asyncio.Task | None = None
|
|
178
200
|
|
|
201
|
+
self._task_logger_internal_app: SACApp | None = None
|
|
202
|
+
self._task_logger_broker_input: BrokerInput | None = None
|
|
203
|
+
self._task_logger_processor_task: asyncio.Task | None = None
|
|
204
|
+
self.task_logger_service: TaskLoggerService | None = None
|
|
205
|
+
|
|
179
206
|
# Initialize SAM Events service for system events
|
|
180
207
|
from ...common.sam_events import SamEventService
|
|
181
208
|
|
|
@@ -185,14 +212,75 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
185
212
|
publish_func=self.publish_a2a,
|
|
186
213
|
)
|
|
187
214
|
|
|
215
|
+
# Initialize data retention service and timer
|
|
216
|
+
self.data_retention_service = None
|
|
217
|
+
self._data_retention_timer_id = None
|
|
218
|
+
data_retention_config = self.get_config("data_retention", {})
|
|
219
|
+
if data_retention_config.get("enabled", True):
|
|
220
|
+
log.info("%s Data retention is enabled. Initializing service and timer...", self.log_identifier)
|
|
221
|
+
|
|
222
|
+
# Import and initialize the DataRetentionService
|
|
223
|
+
from .services.data_retention_service import DataRetentionService
|
|
224
|
+
|
|
225
|
+
session_factory = None
|
|
226
|
+
if self.database_url:
|
|
227
|
+
# SessionLocal will be initialized later in setup_dependencies
|
|
228
|
+
# We'll pass a lambda that returns SessionLocal when called
|
|
229
|
+
session_factory = lambda: dependencies.SessionLocal() if dependencies.SessionLocal else None
|
|
230
|
+
|
|
231
|
+
self.data_retention_service = DataRetentionService(
|
|
232
|
+
session_factory=session_factory,
|
|
233
|
+
config=data_retention_config
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
# Create and start the cleanup timer
|
|
237
|
+
cleanup_interval_hours = data_retention_config.get("cleanup_interval_hours", 24)
|
|
238
|
+
cleanup_interval_ms = cleanup_interval_hours * 60 * 60 * 1000
|
|
239
|
+
self._data_retention_timer_id = f"data_retention_cleanup_{self.gateway_id}"
|
|
240
|
+
|
|
241
|
+
self.add_timer(
|
|
242
|
+
delay_ms=cleanup_interval_ms,
|
|
243
|
+
timer_id=self._data_retention_timer_id,
|
|
244
|
+
interval_ms=cleanup_interval_ms,
|
|
245
|
+
)
|
|
246
|
+
log.info(
|
|
247
|
+
"%s Data retention timer created with ID '%s' and interval %d hours.",
|
|
248
|
+
self.log_identifier,
|
|
249
|
+
self._data_retention_timer_id,
|
|
250
|
+
cleanup_interval_hours,
|
|
251
|
+
)
|
|
252
|
+
else:
|
|
253
|
+
log.info("%s Data retention is disabled via configuration.", self.log_identifier)
|
|
254
|
+
|
|
188
255
|
log.info("%s Web UI Backend Component initialized.", self.log_identifier)
|
|
189
256
|
|
|
190
257
|
def process_event(self, event: Event):
|
|
191
258
|
if event.event_type == EventType.TIMER:
|
|
192
|
-
|
|
259
|
+
timer_id = event.data.get("timer_id")
|
|
260
|
+
|
|
261
|
+
if timer_id == self._sse_cleanup_timer_id:
|
|
193
262
|
log.debug("%s SSE buffer cleanup timer triggered.", self.log_identifier)
|
|
194
263
|
self.sse_event_buffer.cleanup_stale_buffers()
|
|
195
264
|
return
|
|
265
|
+
|
|
266
|
+
if timer_id == self._data_retention_timer_id:
|
|
267
|
+
log.debug("%s Data retention cleanup timer triggered.", self.log_identifier)
|
|
268
|
+
if self.data_retention_service:
|
|
269
|
+
try:
|
|
270
|
+
self.data_retention_service.cleanup_old_data()
|
|
271
|
+
except Exception as e:
|
|
272
|
+
log.error(
|
|
273
|
+
"%s Error during data retention cleanup: %s",
|
|
274
|
+
self.log_identifier,
|
|
275
|
+
e,
|
|
276
|
+
exc_info=True,
|
|
277
|
+
)
|
|
278
|
+
else:
|
|
279
|
+
log.warning(
|
|
280
|
+
"%s Data retention timer fired but service is not initialized.",
|
|
281
|
+
self.log_identifier,
|
|
282
|
+
)
|
|
283
|
+
return
|
|
196
284
|
|
|
197
285
|
super().process_event(event)
|
|
198
286
|
|
|
@@ -270,9 +358,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
270
358
|
forwarder_cfg = {
|
|
271
359
|
"component_class": VisualizationForwarderComponent,
|
|
272
360
|
"component_name": f"{self.gateway_id}_viz_forwarder",
|
|
273
|
-
"component_config": {
|
|
274
|
-
"target_queue_ref": self._visualization_message_queue
|
|
275
|
-
},
|
|
361
|
+
"component_config": {"target_queue_ref": self._visualization_message_queue},
|
|
276
362
|
}
|
|
277
363
|
|
|
278
364
|
flow_config = {
|
|
@@ -355,6 +441,121 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
355
441
|
self._visualization_broker_input = None
|
|
356
442
|
raise
|
|
357
443
|
|
|
444
|
+
def _ensure_task_logger_flow_is_running(self) -> None:
|
|
445
|
+
"""
|
|
446
|
+
Ensures the internal SAC flow for A2A task logging is created and running.
|
|
447
|
+
"""
|
|
448
|
+
log_id_prefix = f"{self.log_identifier}[EnsureTaskLogFlow]"
|
|
449
|
+
if self._task_logger_internal_app is not None:
|
|
450
|
+
log.debug("%s Task logger flow already running.", log_id_prefix)
|
|
451
|
+
return
|
|
452
|
+
|
|
453
|
+
log.info("%s Initializing internal A2A task logger flow...", log_id_prefix)
|
|
454
|
+
try:
|
|
455
|
+
main_app = self.get_app()
|
|
456
|
+
if not main_app or not main_app.connector:
|
|
457
|
+
raise RuntimeError(
|
|
458
|
+
"Main app or connector not available for internal flow creation."
|
|
459
|
+
)
|
|
460
|
+
|
|
461
|
+
main_broker_config = main_app.app_info.get("broker", {})
|
|
462
|
+
if not main_broker_config:
|
|
463
|
+
raise ValueError("Main app broker configuration is missing.")
|
|
464
|
+
|
|
465
|
+
# The task logger needs to see ALL messages.
|
|
466
|
+
subscriptions = [{"topic": f"{self.namespace.rstrip('/')}/a2a/>"}]
|
|
467
|
+
|
|
468
|
+
broker_input_cfg = {
|
|
469
|
+
"component_module": "broker_input",
|
|
470
|
+
"component_name": f"{self.gateway_id}_task_log_broker_input",
|
|
471
|
+
"broker_queue_name": f"{self.namespace.strip('/')}/q/gdk/task_log/{self.gateway_id}/{uuid.uuid4().hex}",
|
|
472
|
+
"create_queue_on_start": True,
|
|
473
|
+
"component_config": {
|
|
474
|
+
"broker_url": main_broker_config.get("broker_url"),
|
|
475
|
+
"broker_username": main_broker_config.get("broker_username"),
|
|
476
|
+
"broker_password": main_broker_config.get("broker_password"),
|
|
477
|
+
"broker_vpn": main_broker_config.get("broker_vpn"),
|
|
478
|
+
"trust_store_path": main_broker_config.get("trust_store_path"),
|
|
479
|
+
"dev_mode": main_broker_config.get("dev_mode"),
|
|
480
|
+
"broker_subscriptions": subscriptions,
|
|
481
|
+
"reconnection_strategy": main_broker_config.get(
|
|
482
|
+
"reconnection_strategy"
|
|
483
|
+
),
|
|
484
|
+
"retry_interval": main_broker_config.get("retry_interval"),
|
|
485
|
+
"retry_count": main_broker_config.get("retry_count"),
|
|
486
|
+
"temporary_queue": True,
|
|
487
|
+
},
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
forwarder_cfg = {
|
|
491
|
+
"component_class": TaskLoggerForwarderComponent,
|
|
492
|
+
"component_name": f"{self.gateway_id}_task_log_forwarder",
|
|
493
|
+
"component_config": {"target_queue_ref": self._task_logger_queue},
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
flow_config = {
|
|
497
|
+
"name": f"{self.gateway_id}_task_log_flow",
|
|
498
|
+
"components": [broker_input_cfg, forwarder_cfg],
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
internal_app_broker_config = main_broker_config.copy()
|
|
502
|
+
internal_app_broker_config["input_enabled"] = True
|
|
503
|
+
internal_app_broker_config["output_enabled"] = False
|
|
504
|
+
|
|
505
|
+
app_config_for_internal_flow = {
|
|
506
|
+
"name": f"{self.gateway_id}_task_log_internal_app",
|
|
507
|
+
"flows": [flow_config],
|
|
508
|
+
"broker": internal_app_broker_config,
|
|
509
|
+
"app_config": {},
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
self._task_logger_internal_app = main_app.connector.create_internal_app(
|
|
513
|
+
app_name=app_config_for_internal_flow["name"],
|
|
514
|
+
flows=app_config_for_internal_flow["flows"],
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
if (
|
|
518
|
+
not self._task_logger_internal_app
|
|
519
|
+
or not self._task_logger_internal_app.flows
|
|
520
|
+
):
|
|
521
|
+
raise RuntimeError("Internal task logger app/flow creation failed.")
|
|
522
|
+
|
|
523
|
+
self._task_logger_internal_app.run()
|
|
524
|
+
log.info("%s Internal task logger app started.", log_id_prefix)
|
|
525
|
+
|
|
526
|
+
flow_instance = self._task_logger_internal_app.flows[0]
|
|
527
|
+
if flow_instance.component_groups and flow_instance.component_groups[0]:
|
|
528
|
+
self._task_logger_broker_input = flow_instance.component_groups[0][0]
|
|
529
|
+
if not isinstance(self._task_logger_broker_input, BrokerInput):
|
|
530
|
+
raise RuntimeError(
|
|
531
|
+
"Task logger flow setup error: BrokerInput not found."
|
|
532
|
+
)
|
|
533
|
+
log.info(
|
|
534
|
+
"%s Obtained reference to internal task logger BrokerInput component.",
|
|
535
|
+
log_id_prefix,
|
|
536
|
+
)
|
|
537
|
+
else:
|
|
538
|
+
raise RuntimeError(
|
|
539
|
+
"Task logger flow setup error: BrokerInput instance not accessible."
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
except Exception as e:
|
|
543
|
+
log.exception(
|
|
544
|
+
"%s Failed to ensure task logger flow is running: %s", log_id_prefix, e
|
|
545
|
+
)
|
|
546
|
+
if self._task_logger_internal_app:
|
|
547
|
+
try:
|
|
548
|
+
self._task_logger_internal_app.cleanup()
|
|
549
|
+
except Exception as cleanup_err:
|
|
550
|
+
log.error(
|
|
551
|
+
"%s Error during cleanup after task logger flow init failure: %s",
|
|
552
|
+
log_id_prefix,
|
|
553
|
+
cleanup_err,
|
|
554
|
+
)
|
|
555
|
+
self._task_logger_internal_app = None
|
|
556
|
+
self._task_logger_broker_input = None
|
|
557
|
+
raise
|
|
558
|
+
|
|
358
559
|
def _resolve_session_config(self) -> dict:
|
|
359
560
|
"""
|
|
360
561
|
Resolve session service configuration with backward compatibility.
|
|
@@ -390,7 +591,6 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
390
591
|
"""
|
|
391
592
|
Asynchronously consumes messages from the _visualization_message_queue,
|
|
392
593
|
filters them, and forwards them to relevant SSE connections.
|
|
393
|
-
Placeholder for Phase 2: Just logs messages.
|
|
394
594
|
"""
|
|
395
595
|
log_id_prefix = f"{self.log_identifier}[VizMsgProcessor]"
|
|
396
596
|
log.info("%s Starting visualization message processor loop...", log_id_prefix)
|
|
@@ -417,7 +617,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
417
617
|
max_size = self._visualization_message_queue.maxsize
|
|
418
618
|
if max_size > 0 and (current_size / max_size) > 0.90:
|
|
419
619
|
log.warning(
|
|
420
|
-
"%s Visualization queue is over 90%% full. Current size: %d/%d",
|
|
620
|
+
"%s Visualization message queue is over 90%% full. Current size: %d/%d",
|
|
421
621
|
log_id_prefix,
|
|
422
622
|
current_size,
|
|
423
623
|
max_size,
|
|
@@ -594,6 +794,59 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
594
794
|
|
|
595
795
|
log.info("%s Visualization message processor loop finished.", log_id_prefix)
|
|
596
796
|
|
|
797
|
+
async def _task_logger_loop(self) -> None:
|
|
798
|
+
"""
|
|
799
|
+
Asynchronously consumes messages from the _task_logger_queue and
|
|
800
|
+
passes them to the TaskLoggerService for persistence.
|
|
801
|
+
"""
|
|
802
|
+
log_id_prefix = f"{self.log_identifier}[TaskLoggerLoop]"
|
|
803
|
+
log.info("%s Starting task logger loop...", log_id_prefix)
|
|
804
|
+
loop = asyncio.get_running_loop()
|
|
805
|
+
|
|
806
|
+
while not self.stop_signal.is_set():
|
|
807
|
+
msg_data = None
|
|
808
|
+
try:
|
|
809
|
+
msg_data = await loop.run_in_executor(
|
|
810
|
+
None,
|
|
811
|
+
self._task_logger_queue.get,
|
|
812
|
+
True,
|
|
813
|
+
1.0,
|
|
814
|
+
)
|
|
815
|
+
|
|
816
|
+
if msg_data is None:
|
|
817
|
+
log.info(
|
|
818
|
+
"%s Received shutdown signal for task logger loop.",
|
|
819
|
+
log_id_prefix,
|
|
820
|
+
)
|
|
821
|
+
break
|
|
822
|
+
|
|
823
|
+
if self.task_logger_service:
|
|
824
|
+
self.task_logger_service.log_event(msg_data)
|
|
825
|
+
else:
|
|
826
|
+
log.warning(
|
|
827
|
+
"%s Task logger service not available. Cannot log event.",
|
|
828
|
+
log_id_prefix,
|
|
829
|
+
)
|
|
830
|
+
|
|
831
|
+
self._task_logger_queue.task_done()
|
|
832
|
+
|
|
833
|
+
except queue.Empty:
|
|
834
|
+
continue
|
|
835
|
+
except asyncio.CancelledError:
|
|
836
|
+
log.info("%s Task logger loop cancelled.", log_id_prefix)
|
|
837
|
+
break
|
|
838
|
+
except Exception as e:
|
|
839
|
+
log.exception(
|
|
840
|
+
"%s Error in task logger loop: %s",
|
|
841
|
+
log_id_prefix,
|
|
842
|
+
e,
|
|
843
|
+
)
|
|
844
|
+
if msg_data and self._task_logger_queue:
|
|
845
|
+
self._task_logger_queue.task_done()
|
|
846
|
+
await asyncio.sleep(1)
|
|
847
|
+
|
|
848
|
+
log.info("%s Task logger loop finished.", log_id_prefix)
|
|
849
|
+
|
|
597
850
|
async def _add_visualization_subscription(
|
|
598
851
|
self, topic_str: str, stream_id: str
|
|
599
852
|
) -> bool:
|
|
@@ -919,6 +1172,18 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
919
1172
|
|
|
920
1173
|
setup_dependencies(self, self.database_url)
|
|
921
1174
|
|
|
1175
|
+
# Instantiate services that depend on the database session factory.
|
|
1176
|
+
# This must be done *after* setup_dependencies has run.
|
|
1177
|
+
session_factory = dependencies.SessionLocal if self.database_url else None
|
|
1178
|
+
task_logging_config = self.get_config("task_logging", {})
|
|
1179
|
+
self.task_logger_service = TaskLoggerService(
|
|
1180
|
+
session_factory=session_factory, config=task_logging_config
|
|
1181
|
+
)
|
|
1182
|
+
log.info(
|
|
1183
|
+
"%s Services dependent on database session factory have been initialized.",
|
|
1184
|
+
self.log_identifier,
|
|
1185
|
+
)
|
|
1186
|
+
|
|
922
1187
|
port = (
|
|
923
1188
|
self.fastapi_https_port
|
|
924
1189
|
if self.ssl_keyfile and self.ssl_certfile
|
|
@@ -976,6 +1241,35 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
976
1241
|
"%s Visualization message processor task already running.",
|
|
977
1242
|
self.log_identifier,
|
|
978
1243
|
)
|
|
1244
|
+
|
|
1245
|
+
task_logging_config = self.get_config("task_logging", {})
|
|
1246
|
+
if task_logging_config.get("enabled", False):
|
|
1247
|
+
log.info(
|
|
1248
|
+
"%s Task logging is enabled. Ensuring flow is running...",
|
|
1249
|
+
self.log_identifier,
|
|
1250
|
+
)
|
|
1251
|
+
self._ensure_task_logger_flow_is_running()
|
|
1252
|
+
|
|
1253
|
+
if (
|
|
1254
|
+
self._task_logger_processor_task is None
|
|
1255
|
+
or self._task_logger_processor_task.done()
|
|
1256
|
+
):
|
|
1257
|
+
log.info(
|
|
1258
|
+
"%s Starting task logger processor task.",
|
|
1259
|
+
self.log_identifier,
|
|
1260
|
+
)
|
|
1261
|
+
self._task_logger_processor_task = (
|
|
1262
|
+
self.fastapi_event_loop.create_task(
|
|
1263
|
+
self._task_logger_loop()
|
|
1264
|
+
)
|
|
1265
|
+
)
|
|
1266
|
+
else:
|
|
1267
|
+
log.info(
|
|
1268
|
+
"%s Task logger processor task already running.",
|
|
1269
|
+
self.log_identifier,
|
|
1270
|
+
)
|
|
1271
|
+
else:
|
|
1272
|
+
log.info("%s Task logging is disabled.", self.log_identifier)
|
|
979
1273
|
else:
|
|
980
1274
|
log.error(
|
|
981
1275
|
"%s FastAPI event loop not captured. Cannot start visualization processor.",
|
|
@@ -990,6 +1284,27 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
990
1284
|
)
|
|
991
1285
|
self.stop_signal.set()
|
|
992
1286
|
|
|
1287
|
+
try:
|
|
1288
|
+
from solace_agent_mesh_enterprise.init_enterprise import start_enterprise_background_tasks
|
|
1289
|
+
log.info("%s Starting enterprise background tasks...", self.log_identifier)
|
|
1290
|
+
await start_enterprise_background_tasks(self)
|
|
1291
|
+
log.info("%s Enterprise background tasks started successfully", self.log_identifier)
|
|
1292
|
+
except ImportError:
|
|
1293
|
+
log.debug("%s Enterprise package not available - skipping background tasks", self.log_identifier)
|
|
1294
|
+
except RuntimeError as enterprise_err:
|
|
1295
|
+
log.warning(
|
|
1296
|
+
"%s Enterprise background tasks disabled: %s - Community features will continue normally",
|
|
1297
|
+
self.log_identifier,
|
|
1298
|
+
enterprise_err
|
|
1299
|
+
)
|
|
1300
|
+
except Exception as enterprise_err:
|
|
1301
|
+
log.error(
|
|
1302
|
+
"%s Failed to start enterprise background tasks: %s - Community features will continue normally",
|
|
1303
|
+
self.log_identifier,
|
|
1304
|
+
enterprise_err,
|
|
1305
|
+
exc_info=True
|
|
1306
|
+
)
|
|
1307
|
+
|
|
993
1308
|
@self.fastapi_app.on_event("shutdown")
|
|
994
1309
|
async def shutdown_event():
|
|
995
1310
|
log.info(
|
|
@@ -997,6 +1312,21 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
997
1312
|
self.log_identifier,
|
|
998
1313
|
)
|
|
999
1314
|
|
|
1315
|
+
try:
|
|
1316
|
+
from solace_agent_mesh_enterprise.init_enterprise import stop_enterprise_background_tasks
|
|
1317
|
+
log.info("%s Stopping enterprise background tasks...", self.log_identifier)
|
|
1318
|
+
await stop_enterprise_background_tasks()
|
|
1319
|
+
log.info("%s Enterprise background tasks stopped", self.log_identifier)
|
|
1320
|
+
except ImportError:
|
|
1321
|
+
log.debug("%s Enterprise package not available - no background tasks to stop", self.log_identifier)
|
|
1322
|
+
except Exception as enterprise_err:
|
|
1323
|
+
log.error(
|
|
1324
|
+
"%s Failed to stop enterprise background tasks: %s",
|
|
1325
|
+
self.log_identifier,
|
|
1326
|
+
enterprise_err,
|
|
1327
|
+
exc_info=True
|
|
1328
|
+
)
|
|
1329
|
+
|
|
1000
1330
|
self.fastapi_thread = threading.Thread(
|
|
1001
1331
|
target=self.uvicorn_server.run, daemon=True, name="FastAPI_Thread"
|
|
1002
1332
|
)
|
|
@@ -1059,10 +1389,23 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1059
1389
|
def cleanup(self):
|
|
1060
1390
|
"""Gracefully shuts down the component and the FastAPI server."""
|
|
1061
1391
|
log.info("%s Cleaning up Web UI Backend Component...", self.log_identifier)
|
|
1392
|
+
|
|
1393
|
+
# Cancel timers
|
|
1062
1394
|
self.cancel_timer(self._sse_cleanup_timer_id)
|
|
1395
|
+
if self._data_retention_timer_id:
|
|
1396
|
+
self.cancel_timer(self._data_retention_timer_id)
|
|
1397
|
+
log.info("%s Cancelled data retention cleanup timer.", self.log_identifier)
|
|
1398
|
+
|
|
1399
|
+
# Clean up data retention service
|
|
1400
|
+
if self.data_retention_service:
|
|
1401
|
+
self.data_retention_service = None
|
|
1402
|
+
log.info("%s Data retention service cleaned up.", self.log_identifier)
|
|
1403
|
+
|
|
1063
1404
|
log.info("%s Cleaning up visualization resources...", self.log_identifier)
|
|
1064
1405
|
if self._visualization_message_queue:
|
|
1065
1406
|
self._visualization_message_queue.put(None)
|
|
1407
|
+
if self._task_logger_queue:
|
|
1408
|
+
self._task_logger_queue.put(None)
|
|
1066
1409
|
|
|
1067
1410
|
if (
|
|
1068
1411
|
self._visualization_processor_task
|
|
@@ -1073,6 +1416,10 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1073
1416
|
)
|
|
1074
1417
|
self._visualization_processor_task.cancel()
|
|
1075
1418
|
|
|
1419
|
+
if self._task_logger_processor_task and not self._task_logger_processor_task.done():
|
|
1420
|
+
log.info("%s Cancelling task logger processor task...", self.log_identifier)
|
|
1421
|
+
self._task_logger_processor_task.cancel()
|
|
1422
|
+
|
|
1076
1423
|
if self._visualization_internal_app:
|
|
1077
1424
|
log.info(
|
|
1078
1425
|
"%s Cleaning up internal visualization app...", self.log_identifier
|
|
@@ -1086,6 +1433,17 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1086
1433
|
e,
|
|
1087
1434
|
)
|
|
1088
1435
|
|
|
1436
|
+
if self._task_logger_internal_app:
|
|
1437
|
+
log.info("%s Cleaning up internal task logger app...", self.log_identifier)
|
|
1438
|
+
try:
|
|
1439
|
+
self._task_logger_internal_app.cleanup()
|
|
1440
|
+
except Exception as e:
|
|
1441
|
+
log.error(
|
|
1442
|
+
"%s Error cleaning up internal task logger app: %s",
|
|
1443
|
+
self.log_identifier,
|
|
1444
|
+
e,
|
|
1445
|
+
)
|
|
1446
|
+
|
|
1089
1447
|
self._active_visualization_streams.clear()
|
|
1090
1448
|
self._global_visualization_subscriptions.clear()
|
|
1091
1449
|
self._cleanup_visualization_locks()
|
|
@@ -1375,6 +1733,10 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1375
1733
|
def get_session_manager(self) -> SessionManager:
|
|
1376
1734
|
return self.session_manager
|
|
1377
1735
|
|
|
1736
|
+
def get_task_logger_service(self) -> TaskLoggerService | None:
|
|
1737
|
+
"""Returns the shared TaskLoggerService instance."""
|
|
1738
|
+
return self.task_logger_service
|
|
1739
|
+
|
|
1378
1740
|
def get_namespace(self) -> str:
|
|
1379
1741
|
return self.namespace
|
|
1380
1742
|
|
|
@@ -1672,60 +2034,6 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1672
2034
|
a2a_task_id,
|
|
1673
2035
|
)
|
|
1674
2036
|
|
|
1675
|
-
# Store final agent response in persistence layer if available
|
|
1676
|
-
if hasattr(self, "database_url") and self.database_url:
|
|
1677
|
-
try:
|
|
1678
|
-
session_id = external_request_context.get("a2a_session_id")
|
|
1679
|
-
user_id = external_request_context.get("user_id_for_a2a")
|
|
1680
|
-
agent_name = external_request_context.get(
|
|
1681
|
-
"target_agent_name", "agent"
|
|
1682
|
-
)
|
|
1683
|
-
|
|
1684
|
-
message_text = ""
|
|
1685
|
-
if task_data.status and task_data.status.message:
|
|
1686
|
-
parts = a2a.get_parts_from_message(task_data.status.message)
|
|
1687
|
-
for part in parts:
|
|
1688
|
-
if hasattr(part, "text") and part.text:
|
|
1689
|
-
if message_text:
|
|
1690
|
-
message_text += "\n"
|
|
1691
|
-
message_text += part.text
|
|
1692
|
-
|
|
1693
|
-
if message_text and session_id and user_id:
|
|
1694
|
-
from .dependencies import SessionLocal, get_session_business_service
|
|
1695
|
-
from ...gateway.http_sse.shared.enums import SenderType
|
|
1696
|
-
|
|
1697
|
-
# For background processing, create simple session wrapper
|
|
1698
|
-
if SessionLocal:
|
|
1699
|
-
db = SessionLocal()
|
|
1700
|
-
try:
|
|
1701
|
-
session_service = get_session_business_service()
|
|
1702
|
-
session_service.add_message_to_session(
|
|
1703
|
-
db=db,
|
|
1704
|
-
session_id=session_id,
|
|
1705
|
-
user_id=user_id,
|
|
1706
|
-
message=message_text,
|
|
1707
|
-
sender_type=SenderType.AGENT,
|
|
1708
|
-
sender_name=agent_name,
|
|
1709
|
-
agent_id=agent_name,
|
|
1710
|
-
)
|
|
1711
|
-
db.commit()
|
|
1712
|
-
except Exception:
|
|
1713
|
-
db.rollback()
|
|
1714
|
-
raise
|
|
1715
|
-
finally:
|
|
1716
|
-
db.close()
|
|
1717
|
-
log.info(
|
|
1718
|
-
"%s Final agent response stored in session %s",
|
|
1719
|
-
log_id_prefix,
|
|
1720
|
-
session_id,
|
|
1721
|
-
)
|
|
1722
|
-
except Exception as storage_error:
|
|
1723
|
-
log.warning(
|
|
1724
|
-
"%s Failed to store final agent response: %s",
|
|
1725
|
-
log_id_prefix,
|
|
1726
|
-
storage_error,
|
|
1727
|
-
)
|
|
1728
|
-
|
|
1729
2037
|
except Exception as e:
|
|
1730
2038
|
log.exception(
|
|
1731
2039
|
"%s Failed to send final_response via SSE for A2A Task ID %s: %s",
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
# DEVELOPER GUIDE: components
|
|
2
2
|
|
|
3
3
|
## Quick Summary
|
|
4
|
-
This directory contains components for the HTTP SSE (Server-Sent Events) gateway
|
|
4
|
+
This directory contains SAC (Solace AI Connector) components for the HTTP SSE (Server-Sent Events) gateway. These components forward messages from Solace broker inputs to internal Python queues, enabling real-time visualization and task logging in web-based user interfaces.
|
|
5
5
|
|
|
6
6
|
## Files Overview
|
|
7
|
-
- `__init__.py` - Makes the `VisualizationForwarderComponent` class directly importable from the
|
|
8
|
-
- `
|
|
7
|
+
- `__init__.py` - Makes the `VisualizationForwarderComponent` class directly importable from the components package
|
|
8
|
+
- `components_llm.txt` - Developer guide documentation for this directory
|
|
9
|
+
- `task_logger_forwarder.py` - SAC component that forwards messages to a task logging queue
|
|
10
|
+
- `visualization_forwarder_component.py` - SAC component that forwards messages to a visualization queue
|
|
9
11
|
|
|
10
12
|
## Developer API Reference
|
|
11
13
|
|
|
@@ -16,12 +18,50 @@ This directory contains components for the HTTP SSE (Server-Sent Events) gateway
|
|
|
16
18
|
**Exports:**
|
|
17
19
|
- `VisualizationForwarderComponent` - The main component class for forwarding messages to a visualization queue
|
|
18
20
|
|
|
21
|
+
### task_logger_forwarder.py
|
|
22
|
+
**Purpose:** A SAC component that forwards messages from a BrokerInput to a target queue for task logging
|
|
23
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.components.task_logger_forwarder import TaskLoggerForwarderComponent`
|
|
24
|
+
|
|
25
|
+
**Classes:**
|
|
26
|
+
- `TaskLoggerForwarderComponent(**kwargs: Any)` - A component that forwards messages to a task logging queue, initialized with configuration parameters including `target_queue_ref`
|
|
27
|
+
- `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
|
|
28
|
+
- `target_queue: queue.Queue` - The queue instance where messages are forwarded
|
|
29
|
+
|
|
30
|
+
**Constants/Variables:**
|
|
31
|
+
- `info: Dict` - Metadata dictionary required by SAC framework describing component configuration, input schema, and purpose
|
|
32
|
+
|
|
33
|
+
**Usage Examples:**
|
|
34
|
+
```python
|
|
35
|
+
import queue
|
|
36
|
+
from solace_agent_mesh.gateway.http_sse.components.task_logger_forwarder import TaskLoggerForwarderComponent
|
|
37
|
+
from solace_ai_connector.common.message import Message as SolaceMessage
|
|
38
|
+
|
|
39
|
+
# 1. Create a target queue for task logging
|
|
40
|
+
task_logging_queue = queue.Queue()
|
|
41
|
+
|
|
42
|
+
# 2. Instantiate the component with target queue reference
|
|
43
|
+
task_forwarder = TaskLoggerForwarderComponent(
|
|
44
|
+
name="task_logger",
|
|
45
|
+
target_queue_ref=task_logging_queue
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# 3. The invoke method is called automatically by SAC framework
|
|
49
|
+
# when messages arrive from connected BrokerInput component
|
|
50
|
+
|
|
51
|
+
# 4. Consume forwarded messages from the queue
|
|
52
|
+
if not task_logging_queue.empty():
|
|
53
|
+
forwarded_data = task_logging_queue.get()
|
|
54
|
+
print(f"Task Topic: {forwarded_data['topic']}")
|
|
55
|
+
print(f"Task Payload: {forwarded_data['payload']}")
|
|
56
|
+
print(f"User Properties: {forwarded_data['user_properties']}")
|
|
57
|
+
```
|
|
58
|
+
|
|
19
59
|
### visualization_forwarder_component.py
|
|
20
|
-
**Purpose:** A
|
|
60
|
+
**Purpose:** A SAC component that forwards messages from a BrokerInput to a target queue for visualization
|
|
21
61
|
**Import:** `from solace_agent_mesh.gateway.http_sse.components.visualization_forwarder_component import VisualizationForwarderComponent`
|
|
22
62
|
|
|
23
63
|
**Classes:**
|
|
24
|
-
- `VisualizationForwarderComponent(**kwargs: Any)` - A component that forwards messages to a
|
|
64
|
+
- `VisualizationForwarderComponent(**kwargs: Any)` - A component that forwards messages to a visualization queue, initialized with configuration parameters including `target_queue_ref`
|
|
25
65
|
- `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
66
|
- `target_queue: queue.Queue` - The queue instance where messages are forwarded
|
|
27
67
|
|
|
@@ -62,4 +102,4 @@ if not visualization_queue.empty():
|
|
|
62
102
|
# }
|
|
63
103
|
```
|
|
64
104
|
|
|
65
|
-
# content_hash:
|
|
105
|
+
# content_hash: 6add2167cb9fdee9ed3e46635d6b4e9391cf062dde9e14dba250a3f33c6c4f73
|