solace-agent-mesh 1.1.0__py3-none-any.whl → 1.3.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.
- solace_agent_mesh/agent/adk/runner.py +18 -12
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/adk/setup.py +141 -34
- solace_agent_mesh/agent/protocol/event_handlers.py +27 -21
- solace_agent_mesh/agent/sac/app.py +0 -1
- solace_agent_mesh/agent/sac/component.py +0 -1
- solace_agent_mesh/agent/tools/__init__.py +1 -0
- solace_agent_mesh/agent/tools/dynamic_tool.py +362 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4e972867.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.071e2d94.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/main.1c79039d.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.858117b7.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +29 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +25 -0
- solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html } +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html } +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +19 -27
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +5 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +63 -0
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
- solace_agent_mesh/assets/docs/lunr-index-1757531604543.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757531604543.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/assets/docs/sitemap.xml +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
- solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
- solace_agent_mesh/cli/commands/run_cmd.py +5 -3
- solace_agent_mesh/cli/utils.py +68 -12
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-CAX9u8a7.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-DXU9SPI5.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C1k9E0aC.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-B0BEKoAR.js +390 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
- solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
- solace_agent_mesh/config_portal/backend/common.py +2 -2
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/evaluation/message_organizer.py +35 -56
- solace_agent_mesh/evaluation/run.py +26 -5
- solace_agent_mesh/evaluation/subscriber.py +35 -10
- solace_agent_mesh/evaluation/summary_builder.py +27 -34
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
- solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
- solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
- solace_agent_mesh/gateway/http_sse/app.py +31 -1
- solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
- solace_agent_mesh/gateway/http_sse/component.py +224 -62
- solace_agent_mesh/gateway/http_sse/dependencies.py +148 -45
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
- solace_agent_mesh/gateway/http_sse/main.py +291 -87
- solace_agent_mesh/gateway/http_sse/routers/{agents.py → agent_cards.py} +7 -7
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +121 -54
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +83 -2
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
- solace_agent_mesh/gateway/http_sse/services/{agent_service.py → agent_card_service.py} +19 -19
- solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
- solace_agent_mesh/templates/shared_config.yaml +4 -5
- solace_agent_mesh/templates/webui.yaml +8 -10
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/METADATA +5 -3
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/RECORD +150 -104
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.8ccb9901.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.c484bf96.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.bf78fbdb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/aba87c2f.76376d7c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.a75ecc0d.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1756992446316.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
- solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +0 -699
- solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -85
- solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
- /solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js.LICENSE.txt → main.1c79039d.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -3,34 +3,37 @@ Custom Solace AI Connector Component to host the FastAPI backend for the Web UI.
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import asyncio
|
|
6
|
-
import queue
|
|
7
|
-
import uuid
|
|
8
6
|
import json
|
|
7
|
+
import queue
|
|
9
8
|
import re
|
|
10
9
|
import threading
|
|
11
|
-
|
|
10
|
+
import uuid
|
|
12
11
|
from datetime import datetime, timezone
|
|
13
|
-
from
|
|
12
|
+
from typing import Any
|
|
14
13
|
|
|
15
14
|
import uvicorn
|
|
16
|
-
from fastapi import FastAPI
|
|
17
|
-
|
|
15
|
+
from fastapi import FastAPI, UploadFile
|
|
16
|
+
from fastapi import Request as FastAPIRequest
|
|
18
17
|
from solace_ai_connector.common.log import log
|
|
18
|
+
from solace_ai_connector.components.inputs_outputs.broker_input import BrokerInput
|
|
19
19
|
from solace_ai_connector.flow.app import App as SACApp
|
|
20
|
-
from solace_ai_connector.components.inputs_outputs.broker_input import (
|
|
21
|
-
BrokerInput,
|
|
22
|
-
)
|
|
23
20
|
|
|
24
|
-
from ...gateway.http_sse.sse_manager import SSEManager
|
|
25
|
-
|
|
26
|
-
from .components import VisualizationForwarderComponent
|
|
27
|
-
from ...gateway.http_sse.session_manager import SessionManager
|
|
28
|
-
from ...gateway.base.component import BaseGatewayComponent
|
|
29
21
|
from ...common.agent_registry import AgentRegistry
|
|
30
22
|
from ...core_a2a.service import CoreA2AService
|
|
31
|
-
from
|
|
23
|
+
from ...gateway.base.component import BaseGatewayComponent
|
|
24
|
+
from ...gateway.http_sse.session_manager import SessionManager
|
|
25
|
+
from ...gateway.http_sse.sse_manager import SSEManager
|
|
26
|
+
from .components import VisualizationForwarderComponent
|
|
27
|
+
from .infrastructure.persistence_service import PersistenceService
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
from google.adk.artifacts import BaseArtifactService
|
|
31
|
+
except ImportError:
|
|
32
|
+
|
|
33
|
+
class BaseArtifactService:
|
|
34
|
+
pass
|
|
35
|
+
|
|
32
36
|
|
|
33
|
-
from ...common.a2a.types import ContentPart
|
|
34
37
|
from a2a.types import (
|
|
35
38
|
A2ARequest,
|
|
36
39
|
AgentCard,
|
|
@@ -40,10 +43,15 @@ from a2a.types import (
|
|
|
40
43
|
TaskArtifactUpdateEvent,
|
|
41
44
|
TaskStatusUpdateEvent,
|
|
42
45
|
)
|
|
46
|
+
|
|
43
47
|
from ...common import a2a
|
|
44
|
-
from ...
|
|
48
|
+
from ...common.a2a.types import ContentPart
|
|
45
49
|
from ...common.middleware.config_resolver import ConfigResolver
|
|
46
|
-
|
|
50
|
+
from ...common.utils.embeds import (
|
|
51
|
+
EARLY_EMBED_TYPES,
|
|
52
|
+
evaluate_embed,
|
|
53
|
+
resolve_embeds_in_string,
|
|
54
|
+
)
|
|
47
55
|
|
|
48
56
|
info = {
|
|
49
57
|
"class_name": "WebUIBackendComponent",
|
|
@@ -114,27 +122,42 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
114
122
|
|
|
115
123
|
self.sse_manager = SSEManager(max_queue_size=sse_max_queue_size)
|
|
116
124
|
|
|
125
|
+
session_config = self._resolve_session_config()
|
|
126
|
+
if session_config.get("type") == "sql":
|
|
127
|
+
# SQL type explicitly configured - database_url is required
|
|
128
|
+
database_url = session_config.get("database_url")
|
|
129
|
+
if not database_url:
|
|
130
|
+
raise ValueError(
|
|
131
|
+
f"{self.log_identifier} Session service type is 'sql' but no database_url provided. "
|
|
132
|
+
"Please provide a database_url in the session_service configuration or use type 'memory'."
|
|
133
|
+
)
|
|
134
|
+
self.persistence_service = PersistenceService(database_url)
|
|
135
|
+
else:
|
|
136
|
+
# Memory storage or no explicit configuration - no persistence service needed
|
|
137
|
+
self.persistence_service = None
|
|
138
|
+
|
|
117
139
|
component_config = self.get_config("component_config", {})
|
|
118
140
|
app_config = component_config.get("app_config", {})
|
|
119
141
|
|
|
120
142
|
self.session_manager = SessionManager(
|
|
121
143
|
secret_key=self.session_secret_key,
|
|
122
144
|
app_config=app_config,
|
|
145
|
+
persistence_service=self.persistence_service,
|
|
123
146
|
)
|
|
124
147
|
|
|
125
|
-
self.fastapi_app:
|
|
126
|
-
self.uvicorn_server:
|
|
127
|
-
self.fastapi_thread:
|
|
128
|
-
self.fastapi_event_loop:
|
|
148
|
+
self.fastapi_app: FastAPI | None = None
|
|
149
|
+
self.uvicorn_server: uvicorn.Server | None = None
|
|
150
|
+
self.fastapi_thread: threading.Thread | None = None
|
|
151
|
+
self.fastapi_event_loop: asyncio.AbstractEventLoop | None = None
|
|
129
152
|
|
|
130
|
-
self._visualization_internal_app:
|
|
131
|
-
self._visualization_broker_input:
|
|
153
|
+
self._visualization_internal_app: SACApp | None = None
|
|
154
|
+
self._visualization_broker_input: BrokerInput | None = None
|
|
132
155
|
self._visualization_message_queue: queue.Queue = queue.Queue(maxsize=200)
|
|
133
|
-
self._active_visualization_streams:
|
|
134
|
-
self._visualization_locks:
|
|
156
|
+
self._active_visualization_streams: dict[str, dict[str, Any]] = {}
|
|
157
|
+
self._visualization_locks: dict[asyncio.AbstractEventLoop, asyncio.Lock] = {}
|
|
135
158
|
self._visualization_locks_lock = threading.Lock()
|
|
136
|
-
self._global_visualization_subscriptions:
|
|
137
|
-
self._visualization_processor_task:
|
|
159
|
+
self._global_visualization_subscriptions: dict[str, int] = {}
|
|
160
|
+
self._visualization_processor_task: asyncio.Task | None = None
|
|
138
161
|
|
|
139
162
|
log.info("%s Web UI Backend Component initialized.", self.log_identifier)
|
|
140
163
|
|
|
@@ -297,6 +320,37 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
297
320
|
self._visualization_broker_input = None
|
|
298
321
|
raise
|
|
299
322
|
|
|
323
|
+
def _resolve_session_config(self) -> dict:
|
|
324
|
+
"""
|
|
325
|
+
Resolve session service configuration with backward compatibility.
|
|
326
|
+
|
|
327
|
+
Priority order:
|
|
328
|
+
1. Component-specific session_service config (new approach)
|
|
329
|
+
2. Shared default_session_service config (deprecated, with warning)
|
|
330
|
+
3. Hardcoded default (SQLite for Web UI)
|
|
331
|
+
"""
|
|
332
|
+
# Check component-specific session_service config first
|
|
333
|
+
component_session_config = self.get_config("session_service")
|
|
334
|
+
if component_session_config:
|
|
335
|
+
log.debug("Using component-specific session_service configuration")
|
|
336
|
+
return component_session_config
|
|
337
|
+
|
|
338
|
+
# Backward compatibility: check shared config
|
|
339
|
+
shared_session_config = self.get_config("default_session_service")
|
|
340
|
+
if shared_session_config:
|
|
341
|
+
log.warning(
|
|
342
|
+
"Using session_service from shared config is deprecated. "
|
|
343
|
+
"Move to component-specific configuration in app_config.session_service"
|
|
344
|
+
)
|
|
345
|
+
return shared_session_config
|
|
346
|
+
|
|
347
|
+
# Default configuration for Web UI (backward compatibility)
|
|
348
|
+
default_config = {"type": "memory", "default_behavior": "PERSISTENT"}
|
|
349
|
+
log.info(
|
|
350
|
+
"Using default memory session configuration for Web UI (backward compatibility)"
|
|
351
|
+
)
|
|
352
|
+
return default_config
|
|
353
|
+
|
|
300
354
|
async def _visualization_message_processor_loop(self) -> None:
|
|
301
355
|
"""
|
|
302
356
|
Asynchronously consumes messages from the _visualization_message_queue,
|
|
@@ -564,7 +618,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
564
618
|
if not hasattr(
|
|
565
619
|
self._visualization_broker_input, "add_subscription"
|
|
566
620
|
) or not callable(
|
|
567
|
-
|
|
621
|
+
self._visualization_broker_input.add_subscription
|
|
568
622
|
):
|
|
569
623
|
log.error(
|
|
570
624
|
"%s Visualization BrokerInput does not support dynamic 'add_subscription'. "
|
|
@@ -679,9 +733,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
679
733
|
try:
|
|
680
734
|
if not hasattr(
|
|
681
735
|
self._visualization_broker_input, "remove_subscription"
|
|
682
|
-
) or not callable(
|
|
683
|
-
getattr(self._visualization_broker_input, "remove_subscription")
|
|
684
|
-
):
|
|
736
|
+
) or not callable(self._visualization_broker_input.remove_subscription):
|
|
685
737
|
log.error(
|
|
686
738
|
"%s Visualization BrokerInput does not support dynamic 'remove_subscription'. "
|
|
687
739
|
"Please upgrade the 'solace-ai-connector' module. Cannot remove subscription '%s'.",
|
|
@@ -768,7 +820,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
768
820
|
|
|
769
821
|
async def _extract_initial_claims(
|
|
770
822
|
self, external_event_data: Any
|
|
771
|
-
) ->
|
|
823
|
+
) -> dict[str, Any] | None:
|
|
772
824
|
"""
|
|
773
825
|
Extracts initial identity claims from the incoming external event.
|
|
774
826
|
For the WebUI, this means inspecting the FastAPIRequest.
|
|
@@ -824,16 +876,12 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
824
876
|
return
|
|
825
877
|
|
|
826
878
|
try:
|
|
827
|
-
from ...gateway.http_sse.main import
|
|
828
|
-
|
|
829
|
-
)
|
|
830
|
-
from ...gateway.http_sse.main import (
|
|
831
|
-
setup_dependencies,
|
|
832
|
-
)
|
|
879
|
+
from ...gateway.http_sse.main import app as fastapi_app_instance
|
|
880
|
+
from ...gateway.http_sse.main import setup_dependencies
|
|
833
881
|
|
|
834
882
|
self.fastapi_app = fastapi_app_instance
|
|
835
883
|
|
|
836
|
-
setup_dependencies(self)
|
|
884
|
+
setup_dependencies(self, self.persistence_service)
|
|
837
885
|
|
|
838
886
|
port = (
|
|
839
887
|
self.fastapi_https_port
|
|
@@ -936,7 +984,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
936
984
|
raise
|
|
937
985
|
|
|
938
986
|
def publish_a2a(
|
|
939
|
-
self, topic: str, payload:
|
|
987
|
+
self, topic: str, payload: dict, user_properties: dict | None = None
|
|
940
988
|
):
|
|
941
989
|
"""
|
|
942
990
|
Publishes an A2A message using the SAC App's send_message method.
|
|
@@ -994,8 +1042,8 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
994
1042
|
log.info("%s Visualization resources cleaned up.", self.log_identifier)
|
|
995
1043
|
|
|
996
1044
|
def _infer_visualization_event_details(
|
|
997
|
-
self, topic: str, payload:
|
|
998
|
-
) ->
|
|
1045
|
+
self, topic: str, payload: dict[str, Any]
|
|
1046
|
+
) -> dict[str, Any]:
|
|
999
1047
|
"""
|
|
1000
1048
|
Infers details for the visualization SSE payload from the Solace topic and A2A message.
|
|
1001
1049
|
This version is updated to parse the official A2A SDK message formats.
|
|
@@ -1135,19 +1183,19 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1135
1183
|
(summary_str[:100] + "...") if len(summary_str) > 100 else summary_str
|
|
1136
1184
|
)
|
|
1137
1185
|
except Exception:
|
|
1138
|
-
details["payload_summary"][
|
|
1139
|
-
"
|
|
1140
|
-
|
|
1186
|
+
details["payload_summary"]["params_preview"] = (
|
|
1187
|
+
"[Could not serialize payload]"
|
|
1188
|
+
)
|
|
1141
1189
|
|
|
1142
1190
|
return details
|
|
1143
1191
|
|
|
1144
1192
|
def _extract_involved_agents_for_viz(
|
|
1145
|
-
self, topic: str, payload_dict:
|
|
1146
|
-
) ->
|
|
1193
|
+
self, topic: str, payload_dict: dict[str, Any]
|
|
1194
|
+
) -> set[str]:
|
|
1147
1195
|
"""
|
|
1148
1196
|
Extracts agent names involved in a message from its topic and payload.
|
|
1149
1197
|
"""
|
|
1150
|
-
agents:
|
|
1198
|
+
agents: set[str] = set()
|
|
1151
1199
|
log_id_prefix = f"{self.log_identifier}[ExtractAgentsViz]"
|
|
1152
1200
|
|
|
1153
1201
|
topic_agent_match = re.match(
|
|
@@ -1274,13 +1322,13 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1274
1322
|
"""Returns the unique identifier for this gateway instance."""
|
|
1275
1323
|
return self.gateway_id
|
|
1276
1324
|
|
|
1277
|
-
def get_cors_origins(self) ->
|
|
1325
|
+
def get_cors_origins(self) -> list[str]:
|
|
1278
1326
|
return self.cors_allowed_origins
|
|
1279
1327
|
|
|
1280
|
-
def get_shared_artifact_service(self) ->
|
|
1328
|
+
def get_shared_artifact_service(self) -> BaseArtifactService | None:
|
|
1281
1329
|
return self.shared_artifact_service
|
|
1282
1330
|
|
|
1283
|
-
def get_embed_config(self) ->
|
|
1331
|
+
def get_embed_config(self) -> dict[str, Any]:
|
|
1284
1332
|
"""Returns embed-related configuration needed by dependencies."""
|
|
1285
1333
|
return {
|
|
1286
1334
|
"enable_embed_resolution": self.enable_embed_resolution,
|
|
@@ -1296,6 +1344,52 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1296
1344
|
"""Returns the instance of the ConfigResolver."""
|
|
1297
1345
|
return self._config_resolver
|
|
1298
1346
|
|
|
1347
|
+
async def _resolve_embeds_for_persistence(
|
|
1348
|
+
self, message_content: str, session_id: str, user_id: str, log_identifier: str
|
|
1349
|
+
) -> str:
|
|
1350
|
+
"""
|
|
1351
|
+
Resolves embeds in a message for database storage.
|
|
1352
|
+
Returns the resolved text.
|
|
1353
|
+
|
|
1354
|
+
Args:
|
|
1355
|
+
message_content: The message text that may contain embeds
|
|
1356
|
+
session_id: The A2A session ID
|
|
1357
|
+
user_id: The user ID
|
|
1358
|
+
log_identifier: Logging identifier
|
|
1359
|
+
|
|
1360
|
+
Returns:
|
|
1361
|
+
The message with embeds resolved (or original if resolution fails)
|
|
1362
|
+
"""
|
|
1363
|
+
try:
|
|
1364
|
+
embed_context = {
|
|
1365
|
+
"artifact_service": self.shared_artifact_service,
|
|
1366
|
+
"session_context": {
|
|
1367
|
+
"app_name": self.gateway_id,
|
|
1368
|
+
"user_id": user_id,
|
|
1369
|
+
"session_id": session_id,
|
|
1370
|
+
},
|
|
1371
|
+
"config": self.get_embed_config(),
|
|
1372
|
+
}
|
|
1373
|
+
|
|
1374
|
+
resolved_text, _, _ = await resolve_embeds_in_string(
|
|
1375
|
+
text=message_content,
|
|
1376
|
+
context=embed_context,
|
|
1377
|
+
resolver_func=evaluate_embed,
|
|
1378
|
+
types_to_resolve=EARLY_EMBED_TYPES,
|
|
1379
|
+
log_identifier=log_identifier,
|
|
1380
|
+
config=embed_context["config"],
|
|
1381
|
+
)
|
|
1382
|
+
|
|
1383
|
+
return resolved_text
|
|
1384
|
+
|
|
1385
|
+
except Exception as e:
|
|
1386
|
+
log.warning(
|
|
1387
|
+
"%s Error resolving embeds for storage: %s. Using original message.",
|
|
1388
|
+
log_identifier,
|
|
1389
|
+
e,
|
|
1390
|
+
)
|
|
1391
|
+
return message_content
|
|
1392
|
+
|
|
1299
1393
|
def _start_listener(self) -> None:
|
|
1300
1394
|
"""
|
|
1301
1395
|
GDK Hook: Starts the FastAPI/Uvicorn server.
|
|
@@ -1317,8 +1411,8 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1317
1411
|
pass
|
|
1318
1412
|
|
|
1319
1413
|
async def _translate_external_input(
|
|
1320
|
-
self, external_event_data:
|
|
1321
|
-
) ->
|
|
1414
|
+
self, external_event_data: dict[str, Any]
|
|
1415
|
+
) -> tuple[str, list[ContentPart], dict[str, Any]]:
|
|
1322
1416
|
"""
|
|
1323
1417
|
Translates raw HTTP request data (from FastAPI form) into A2A task parameters.
|
|
1324
1418
|
|
|
@@ -1342,10 +1436,9 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1342
1436
|
|
|
1343
1437
|
target_agent_name: str = external_event_data.get("agent_name")
|
|
1344
1438
|
user_message: str = external_event_data.get("message", "")
|
|
1345
|
-
files:
|
|
1439
|
+
files: list[UploadFile] | None = external_event_data.get("files")
|
|
1346
1440
|
client_id: str = external_event_data.get("client_id")
|
|
1347
1441
|
a2a_session_id: str = external_event_data.get("a2a_session_id")
|
|
1348
|
-
|
|
1349
1442
|
if not target_agent_name:
|
|
1350
1443
|
raise ValueError("Target agent name is missing in external_event_data.")
|
|
1351
1444
|
if not client_id or not a2a_session_id:
|
|
@@ -1353,7 +1446,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1353
1446
|
"Client ID or A2A Session ID is missing in external_event_data."
|
|
1354
1447
|
)
|
|
1355
1448
|
|
|
1356
|
-
a2a_parts:
|
|
1449
|
+
a2a_parts: list[ContentPart] = []
|
|
1357
1450
|
|
|
1358
1451
|
if files:
|
|
1359
1452
|
for upload_file in files:
|
|
@@ -1413,18 +1506,24 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1413
1506
|
|
|
1414
1507
|
async def _send_update_to_external(
|
|
1415
1508
|
self,
|
|
1416
|
-
external_request_context:
|
|
1417
|
-
event_data:
|
|
1509
|
+
external_request_context: dict[str, Any],
|
|
1510
|
+
event_data: TaskStatusUpdateEvent | TaskArtifactUpdateEvent,
|
|
1418
1511
|
is_final_chunk_of_update: bool,
|
|
1419
1512
|
) -> None:
|
|
1420
1513
|
"""
|
|
1421
1514
|
Sends an intermediate update (TaskStatusUpdateEvent or TaskArtifactUpdateEvent)
|
|
1422
|
-
to the external platform (Web UI via SSE).
|
|
1515
|
+
to the external platform (Web UI via SSE) and stores agent messages in the database.
|
|
1423
1516
|
"""
|
|
1424
1517
|
log_id_prefix = f"{self.log_identifier}[SendUpdate]"
|
|
1425
1518
|
sse_task_id = external_request_context.get("a2a_task_id_for_event")
|
|
1426
1519
|
a2a_task_id = event_data.task_id
|
|
1427
1520
|
|
|
1521
|
+
log.debug(
|
|
1522
|
+
"%s _send_update_to_external called with event_type: %s",
|
|
1523
|
+
log_id_prefix,
|
|
1524
|
+
type(event_data).__name__,
|
|
1525
|
+
)
|
|
1526
|
+
|
|
1428
1527
|
if not sse_task_id:
|
|
1429
1528
|
log.error(
|
|
1430
1529
|
"%s Cannot send update: 'a2a_task_id_for_event' missing from external_request_context.",
|
|
@@ -1459,6 +1558,10 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1459
1558
|
sse_event_type,
|
|
1460
1559
|
a2a_task_id,
|
|
1461
1560
|
)
|
|
1561
|
+
|
|
1562
|
+
# Note: Agent message storage is handled in _send_final_response_to_external
|
|
1563
|
+
# to avoid duplicate storage of intermediate status updates
|
|
1564
|
+
|
|
1462
1565
|
except Exception as e:
|
|
1463
1566
|
log.exception(
|
|
1464
1567
|
"%s Failed to send %s via SSE for A2A Task ID %s: %s",
|
|
@@ -1469,7 +1572,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1469
1572
|
)
|
|
1470
1573
|
|
|
1471
1574
|
async def _send_final_response_to_external(
|
|
1472
|
-
self, external_request_context:
|
|
1575
|
+
self, external_request_context: dict[str, Any], task_data: Task
|
|
1473
1576
|
) -> None:
|
|
1474
1577
|
"""
|
|
1475
1578
|
Sends the final A2A Task result to the external platform (Web UI via SSE).
|
|
@@ -1478,6 +1581,8 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1478
1581
|
sse_task_id = external_request_context.get("a2a_task_id_for_event")
|
|
1479
1582
|
a2a_task_id = task_data.id
|
|
1480
1583
|
|
|
1584
|
+
log.debug("%s _send_final_response_to_external called", log_id_prefix)
|
|
1585
|
+
|
|
1481
1586
|
if not sse_task_id:
|
|
1482
1587
|
log.error(
|
|
1483
1588
|
"%s Cannot send final response: 'a2a_task_id_for_event' missing from external_request_context.",
|
|
@@ -1506,6 +1611,63 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1506
1611
|
log_id_prefix,
|
|
1507
1612
|
a2a_task_id,
|
|
1508
1613
|
)
|
|
1614
|
+
|
|
1615
|
+
# Store final agent response in persistence layer if available
|
|
1616
|
+
if hasattr(self, "persistence_service") and self.persistence_service:
|
|
1617
|
+
try:
|
|
1618
|
+
session_id = external_request_context.get("a2a_session_id")
|
|
1619
|
+
user_id = external_request_context.get("user_id_for_a2a")
|
|
1620
|
+
agent_name = external_request_context.get(
|
|
1621
|
+
"target_agent_name", "agent"
|
|
1622
|
+
)
|
|
1623
|
+
|
|
1624
|
+
# Extract message content from the task status
|
|
1625
|
+
message_text = ""
|
|
1626
|
+
if task_data.status and task_data.status.message:
|
|
1627
|
+
parts = a2a.get_parts_from_message(task_data.status.message)
|
|
1628
|
+
for part in parts:
|
|
1629
|
+
if hasattr(part, "text") and part.text:
|
|
1630
|
+
if message_text:
|
|
1631
|
+
message_text += "\n"
|
|
1632
|
+
message_text += part.text
|
|
1633
|
+
|
|
1634
|
+
log.info(
|
|
1635
|
+
"%s Final agent response storage debug - session_id: %s, user_id: %s, message_text: '%s', parts_count: %s",
|
|
1636
|
+
log_id_prefix,
|
|
1637
|
+
session_id,
|
|
1638
|
+
user_id,
|
|
1639
|
+
message_text[:100] if message_text else None,
|
|
1640
|
+
len(a2a.get_parts_from_message(task_data.status.message))
|
|
1641
|
+
if task_data.status and task_data.status.message
|
|
1642
|
+
else 0,
|
|
1643
|
+
)
|
|
1644
|
+
|
|
1645
|
+
if message_text and session_id and user_id:
|
|
1646
|
+
from .dependencies import get_session_service
|
|
1647
|
+
from .shared.enums import SenderType
|
|
1648
|
+
|
|
1649
|
+
session_service = get_session_service(self)
|
|
1650
|
+
session_service.add_message_to_session(
|
|
1651
|
+
session_id=session_id,
|
|
1652
|
+
user_id=user_id,
|
|
1653
|
+
message=message_text,
|
|
1654
|
+
sender_type=SenderType.AGENT,
|
|
1655
|
+
sender_name=agent_name,
|
|
1656
|
+
agent_id=agent_name,
|
|
1657
|
+
)
|
|
1658
|
+
log.info(
|
|
1659
|
+
"%s Final agent response stored in session %s",
|
|
1660
|
+
log_id_prefix,
|
|
1661
|
+
session_id,
|
|
1662
|
+
)
|
|
1663
|
+
except Exception as storage_error:
|
|
1664
|
+
log.warning(
|
|
1665
|
+
"%s Failed to store final agent response: %s",
|
|
1666
|
+
log_id_prefix,
|
|
1667
|
+
storage_error,
|
|
1668
|
+
)
|
|
1669
|
+
# Don't fail the SSE send if storage fails
|
|
1670
|
+
|
|
1509
1671
|
except Exception as e:
|
|
1510
1672
|
log.exception(
|
|
1511
1673
|
"%s Failed to send final_response via SSE for A2A Task ID %s: %s",
|
|
@@ -1522,7 +1684,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1522
1684
|
)
|
|
1523
1685
|
|
|
1524
1686
|
async def _send_error_to_external(
|
|
1525
|
-
self, external_request_context:
|
|
1687
|
+
self, external_request_context: dict[str, Any], error_data: JSONRPCError
|
|
1526
1688
|
) -> None:
|
|
1527
1689
|
"""
|
|
1528
1690
|
Sends an error notification to the external platform (Web UI via SSE).
|