solace-agent-mesh 1.4.5__py3-none-any.whl → 1.4.7__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 +24 -8
- solace_agent_mesh/agent/sac/component.py +35 -21
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/{04989206.b9dfe831.js → 04989206.a248f00c.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/166ab619.bdddc63a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{1c6e87d2.43771adc.js → 1c6e87d2.e056b7e0.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4736f2d8.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{4c2787c2.fc6804f2.js → 4c2787c2.c1290a40.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/{5b4258a4.dff11eca.js → 5b4258a4.fdfd2325.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/{75384d09.abdf9cf9.js → 75384d09.1e7d7cb7.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/85387663.be2bc838.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.16e00776.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a12a4955.25fbed32.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.6def8980.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.5fe5203f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/bac0be12.bf0181cf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/beecea0d.ce915979.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cee5d587.47904f5e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f284c35a.525933db.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f897a61a.126663fe.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{fbfa3e75.aca209c9.js → fbfa3e75.e144b16c.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/main.11f9f9f3.js +2 -0
- solace_agent_mesh/assets/docs/assets/js/runtime~main.5922bcf0.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +5 -4
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/rbac-setup-guilde/index.html +201 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +4 -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 +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
- 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 +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 +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +6 -6
- 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 +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +5 -5
- 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 +6 -6
- 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 +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 +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 +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +6 -6
- solace_agent_mesh/assets/docs/lunr-index-1759151175744.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1759151175744.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/client/webui/frontend/static/assets/main-BKIoiLSu.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-ChRwcV89.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/index.html +2 -2
- solace_agent_mesh/gateway/http_sse/alembic/versions/20250916_f6e7d8c9b0a1_convert_timestamps_to_epoch_and_align_columns.py +112 -42
- solace_agent_mesh/gateway/http_sse/app.py +0 -28
- solace_agent_mesh/gateway/http_sse/component.py +29 -15
- solace_agent_mesh/gateway/http_sse/main.py +29 -13
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +39 -1
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +30 -40
- solace_agent_mesh/gateway/http_sse/services/session_service.py +18 -2
- {solace_agent_mesh-1.4.5.dist-info → solace_agent_mesh-1.4.7.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.4.5.dist-info → solace_agent_mesh-1.4.7.dist-info}/RECORD +84 -82
- solace_agent_mesh/assets/docs/assets/js/166ab619.e8f3a7c7.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/483cef9a.8d318c2f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/85387663.6bf41934.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/945fb41e.abf2be91.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.1d029b81.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.7c73bc4f.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/bac0be12.27ee2c26.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/beecea0d.8bbd852c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cee5d587.f1e1ca86.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.2b2f5048.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f897a61a.bc634a3e.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/main.2b4fe82a.js +0 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.c0805958.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1758644347760.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1758644347760.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-8xbvgfVK.css +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/main-B67MsY-v.js +0 -339
- /solace_agent_mesh/assets/docs/assets/js/{main.2b4fe82a.js.LICENSE.txt → main.11f9f9f3.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.4.5.dist-info → solace_agent_mesh-1.4.7.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.4.5.dist-info → solace_agent_mesh-1.4.7.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.4.5.dist-info → solace_agent_mesh-1.4.7.dist-info}/licenses/LICENSE +0 -0
|
@@ -131,7 +131,9 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
131
131
|
)
|
|
132
132
|
|
|
133
133
|
self._sse_cleanup_timer_id = f"sse_cleanup_{self.gateway_id}"
|
|
134
|
-
cleanup_interval_sec = self.get_config(
|
|
134
|
+
cleanup_interval_sec = self.get_config(
|
|
135
|
+
"sse_buffer_cleanup_interval_seconds", 300
|
|
136
|
+
)
|
|
135
137
|
self.add_timer(
|
|
136
138
|
delay_ms=cleanup_interval_sec * 1000,
|
|
137
139
|
timer_id=self._sse_cleanup_timer_id,
|
|
@@ -173,13 +175,14 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
173
175
|
self._visualization_locks_lock = threading.Lock()
|
|
174
176
|
self._global_visualization_subscriptions: dict[str, int] = {}
|
|
175
177
|
self._visualization_processor_task: asyncio.Task | None = None
|
|
176
|
-
|
|
178
|
+
|
|
177
179
|
# Initialize SAM Events service for system events
|
|
178
180
|
from ...common.sam_events import SamEventService
|
|
181
|
+
|
|
179
182
|
self.sam_events = SamEventService(
|
|
180
183
|
namespace=self.namespace,
|
|
181
|
-
component_name=f"{self.name}_gateway",
|
|
182
|
-
publish_func=self.publish_a2a
|
|
184
|
+
component_name=f"{self.name}_gateway",
|
|
185
|
+
publish_func=self.publish_a2a,
|
|
183
186
|
)
|
|
184
187
|
|
|
185
188
|
log.info("%s Web UI Backend Component initialized.", self.log_identifier)
|
|
@@ -1007,7 +1010,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1007
1010
|
)
|
|
1008
1011
|
|
|
1009
1012
|
except Exception as e:
|
|
1010
|
-
log.
|
|
1013
|
+
log.error(
|
|
1011
1014
|
"%s [_start_listener] Failed to start FastAPI/Uvicorn server: %s",
|
|
1012
1015
|
self.log_identifier,
|
|
1013
1016
|
e,
|
|
@@ -1024,12 +1027,16 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1024
1027
|
It's thread-safe as it uses the SAC App instance.
|
|
1025
1028
|
"""
|
|
1026
1029
|
log.debug(f"[publish_a2a] Starting to publish message to topic: {topic}")
|
|
1027
|
-
log.debug(
|
|
1030
|
+
log.debug(
|
|
1031
|
+
f"[publish_a2a] Payload type: {type(payload)}, size: {len(str(payload))} chars"
|
|
1032
|
+
)
|
|
1028
1033
|
log.debug(f"[publish_a2a] User properties: {user_properties}")
|
|
1029
|
-
|
|
1034
|
+
|
|
1030
1035
|
try:
|
|
1031
1036
|
super().publish_a2a_message(payload, topic, user_properties)
|
|
1032
|
-
log.debug(
|
|
1037
|
+
log.debug(
|
|
1038
|
+
f"[publish_a2a] Successfully called super().publish_a2a_message for topic: {topic}"
|
|
1039
|
+
)
|
|
1033
1040
|
except Exception as e:
|
|
1034
1041
|
log.error(f"[publish_a2a] Exception in publish_a2a: {e}", exc_info=True)
|
|
1035
1042
|
raise
|
|
@@ -1143,7 +1150,7 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1143
1150
|
details["source_entity"] = payload.get("source_component", "unknown")
|
|
1144
1151
|
details["target_entity"] = "system"
|
|
1145
1152
|
return details
|
|
1146
|
-
|
|
1153
|
+
|
|
1147
1154
|
# Try to parse as a JSON-RPC response first
|
|
1148
1155
|
if "result" in payload or "error" in payload:
|
|
1149
1156
|
rpc_response = JSONRPCResponse.model_validate(payload)
|
|
@@ -1264,9 +1271,9 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1264
1271
|
(summary_str[:100] + "...") if len(summary_str) > 100 else summary_str
|
|
1265
1272
|
)
|
|
1266
1273
|
except Exception:
|
|
1267
|
-
details["payload_summary"][
|
|
1268
|
-
"
|
|
1269
|
-
|
|
1274
|
+
details["payload_summary"][
|
|
1275
|
+
"params_preview"
|
|
1276
|
+
] = "[Could not serialize payload]"
|
|
1270
1277
|
|
|
1271
1278
|
return details
|
|
1272
1279
|
|
|
@@ -1669,7 +1676,9 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1669
1676
|
try:
|
|
1670
1677
|
session_id = external_request_context.get("a2a_session_id")
|
|
1671
1678
|
user_id = external_request_context.get("user_id_for_a2a")
|
|
1672
|
-
agent_name = external_request_context.get(
|
|
1679
|
+
agent_name = external_request_context.get(
|
|
1680
|
+
"target_agent_name", "agent"
|
|
1681
|
+
)
|
|
1673
1682
|
|
|
1674
1683
|
message_text = ""
|
|
1675
1684
|
if task_data.status and task_data.status.message:
|
|
@@ -1681,10 +1690,15 @@ class WebUIBackendComponent(BaseGatewayComponent):
|
|
|
1681
1690
|
message_text += part.text
|
|
1682
1691
|
|
|
1683
1692
|
if message_text and session_id and user_id:
|
|
1684
|
-
from .dependencies import
|
|
1693
|
+
from .dependencies import (
|
|
1694
|
+
create_session_service_with_transaction,
|
|
1695
|
+
)
|
|
1685
1696
|
from ...gateway.http_sse.shared.enums import SenderType
|
|
1686
1697
|
|
|
1687
|
-
with create_session_service_with_transaction() as (
|
|
1698
|
+
with create_session_service_with_transaction() as (
|
|
1699
|
+
session_service,
|
|
1700
|
+
db,
|
|
1701
|
+
):
|
|
1688
1702
|
session_service.add_message_to_session(
|
|
1689
1703
|
session_id=session_id,
|
|
1690
1704
|
user_id=user_id,
|
|
@@ -310,38 +310,48 @@ def _setup_alembic_config(database_url: str) -> Config:
|
|
|
310
310
|
|
|
311
311
|
|
|
312
312
|
def _run_community_migrations(database_url: str) -> None:
|
|
313
|
+
"""
|
|
314
|
+
Run Alembic migrations for the community database schema.
|
|
315
|
+
This includes sessions, chat_messages tables and their indexes.
|
|
316
|
+
"""
|
|
313
317
|
try:
|
|
314
318
|
from sqlalchemy import create_engine
|
|
315
319
|
|
|
320
|
+
log.info("Starting community migrations...")
|
|
316
321
|
engine = create_engine(database_url)
|
|
317
322
|
inspector = sa.inspect(engine)
|
|
318
323
|
existing_tables = inspector.get_table_names()
|
|
319
324
|
|
|
320
325
|
if not existing_tables or "sessions" not in existing_tables:
|
|
321
|
-
log.info("Running community database
|
|
326
|
+
log.info("Running initial community database setup")
|
|
322
327
|
alembic_cfg = _setup_alembic_config(database_url)
|
|
323
328
|
command.upgrade(alembic_cfg, "head")
|
|
324
|
-
log.info("Community database migrations
|
|
329
|
+
log.info("Community database migrations completed")
|
|
325
330
|
else:
|
|
326
|
-
log.info(
|
|
327
|
-
|
|
328
|
-
)
|
|
331
|
+
log.info("Checking for community schema updates")
|
|
332
|
+
alembic_cfg = _setup_alembic_config(database_url)
|
|
333
|
+
command.upgrade(alembic_cfg, "head")
|
|
334
|
+
log.info("Community database schema is current")
|
|
329
335
|
except Exception as e:
|
|
330
336
|
log.warning(
|
|
331
|
-
"Community migration check failed
|
|
337
|
+
"Community migration check failed: %s - attempting to run migrations",
|
|
332
338
|
e,
|
|
333
339
|
)
|
|
334
340
|
try:
|
|
335
341
|
alembic_cfg = _setup_alembic_config(database_url)
|
|
336
342
|
command.upgrade(alembic_cfg, "head")
|
|
337
|
-
log.info("Community database migrations
|
|
343
|
+
log.info("Community database migrations completed")
|
|
338
344
|
except Exception as migration_error:
|
|
339
|
-
log.
|
|
340
|
-
|
|
341
|
-
)
|
|
345
|
+
log.error("Community migration failed: %s", migration_error)
|
|
346
|
+
log.error("Check database connectivity and permissions")
|
|
347
|
+
raise RuntimeError(f"Community database migration failed: {migration_error}") from migration_error
|
|
342
348
|
|
|
343
349
|
|
|
344
350
|
def _run_enterprise_migrations(component: "WebUIBackendComponent", database_url: str) -> None:
|
|
351
|
+
"""
|
|
352
|
+
Run migrations for enterprise features like advanced analytics, audit logs, etc.
|
|
353
|
+
This is optional and only runs if the enterprise package is available.
|
|
354
|
+
"""
|
|
345
355
|
try:
|
|
346
356
|
from solace_agent_mesh_enterprise.webui_backend.migration_runner import (
|
|
347
357
|
run_migrations,
|
|
@@ -349,19 +359,25 @@ def _run_enterprise_migrations(component: "WebUIBackendComponent", database_url:
|
|
|
349
359
|
|
|
350
360
|
webui_app = component.get_app()
|
|
351
361
|
app_config = getattr(webui_app, "app_config", {}) if webui_app else {}
|
|
352
|
-
log.info("
|
|
362
|
+
log.info("Starting enterprise migrations...")
|
|
353
363
|
run_migrations(database_url, app_config)
|
|
354
364
|
log.info("Enterprise migrations completed")
|
|
355
365
|
except (ImportError, ModuleNotFoundError):
|
|
356
366
|
log.debug("Enterprise module not found - skipping enterprise migrations")
|
|
357
367
|
except Exception as e:
|
|
358
|
-
log.
|
|
368
|
+
log.error("Enterprise migration failed: %s", e)
|
|
369
|
+
log.error("Advanced features may be unavailable")
|
|
370
|
+
raise RuntimeError(f"Enterprise database migration failed: {e}") from e
|
|
359
371
|
|
|
360
372
|
|
|
361
373
|
def _setup_database(component: "WebUIBackendComponent", database_url: str) -> None:
|
|
374
|
+
"""
|
|
375
|
+
Initialize database connection and run all required migrations.
|
|
376
|
+
This sets up both community and enterprise database schemas.
|
|
377
|
+
"""
|
|
362
378
|
dependencies.init_database(database_url)
|
|
363
379
|
log.info("Persistence enabled - sessions will be stored in database")
|
|
364
|
-
log.info("
|
|
380
|
+
log.info("Running database migrations...")
|
|
365
381
|
|
|
366
382
|
_run_community_migrations(database_url)
|
|
367
383
|
_run_enterprise_migrations(component, database_url)
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from fastapi import APIRouter, Body, Depends, HTTPException, status
|
|
2
|
+
from fastapi import Request as FastAPIRequest
|
|
2
3
|
from solace_ai_connector.common.log import log
|
|
3
4
|
|
|
4
|
-
from
|
|
5
|
+
from a2a.types import JSONRPCSuccessResponse
|
|
6
|
+
from ..dependencies import get_session_business_service, get_session_manager
|
|
5
7
|
from ..services.session_service import SessionService
|
|
8
|
+
from ..session_manager import SessionManager
|
|
6
9
|
from ..shared.auth_utils import get_current_user
|
|
7
10
|
from .dto.requests.session_requests import (
|
|
8
11
|
GetSessionHistoryRequest,
|
|
@@ -15,10 +18,45 @@ from .dto.responses.session_responses import (
|
|
|
15
18
|
SessionListResponse,
|
|
16
19
|
SessionResponse,
|
|
17
20
|
)
|
|
21
|
+
from ....common.a2a import create_generic_success_response
|
|
18
22
|
|
|
19
23
|
router = APIRouter()
|
|
20
24
|
|
|
21
25
|
|
|
26
|
+
@router.post("/sessions/new", response_model=JSONRPCSuccessResponse)
|
|
27
|
+
async def create_new_session(
|
|
28
|
+
request: FastAPIRequest,
|
|
29
|
+
user: dict = Depends(get_current_user),
|
|
30
|
+
session_manager: SessionManager = Depends(get_session_manager),
|
|
31
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
32
|
+
):
|
|
33
|
+
"""Creates a new session on-demand and returns its ID."""
|
|
34
|
+
user_id = user.get("id")
|
|
35
|
+
log.info("User %s requesting new session", user_id)
|
|
36
|
+
try:
|
|
37
|
+
new_session_id = session_manager.create_new_session_id(request)
|
|
38
|
+
log.info("Created new session ID: %s for user %s", new_session_id, user_id)
|
|
39
|
+
|
|
40
|
+
# Attempt to create the session record in the DB.
|
|
41
|
+
# The service will handle the check for whether persistence is enabled.
|
|
42
|
+
session_service.create_session(
|
|
43
|
+
user_id=user_id,
|
|
44
|
+
agent_id=None, # Agent is not known at this point
|
|
45
|
+
name=None,
|
|
46
|
+
session_id=new_session_id,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
return create_generic_success_response(
|
|
50
|
+
result={"id": new_session_id}, request_id=None
|
|
51
|
+
)
|
|
52
|
+
except Exception as e:
|
|
53
|
+
log.error("Error creating new session for user %s: %s", user_id, e)
|
|
54
|
+
raise HTTPException(
|
|
55
|
+
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
|
|
56
|
+
detail="Failed to create a new session",
|
|
57
|
+
)
|
|
58
|
+
|
|
59
|
+
|
|
22
60
|
@router.get("/sessions", response_model=SessionListResponse)
|
|
23
61
|
async def get_all_sessions(
|
|
24
62
|
user: dict = Depends(get_current_user),
|
|
@@ -76,28 +76,31 @@ async def _submit_task(
|
|
|
76
76
|
)
|
|
77
77
|
|
|
78
78
|
client_id = session_manager.get_a2a_client_id(request)
|
|
79
|
-
|
|
79
|
+
|
|
80
80
|
# Use session ID from frontend request (contextId) instead of cookie-based session
|
|
81
81
|
# Handle various falsy values: None, empty string, whitespace-only string
|
|
82
|
-
log.info("%s[DEBUG] payload.params.message: %s", log_prefix, payload.params.message)
|
|
83
|
-
log.info("%s[DEBUG] hasattr context_id: %s", log_prefix, hasattr(payload.params.message, 'context_id'))
|
|
84
|
-
if hasattr(payload.params.message, 'context_id'):
|
|
85
|
-
log.info("%s[DEBUG] context_id value: %s", log_prefix, payload.params.message.context_id)
|
|
86
|
-
|
|
87
82
|
frontend_session_id = None
|
|
88
|
-
if
|
|
83
|
+
if (
|
|
84
|
+
hasattr(payload.params.message, "context_id")
|
|
85
|
+
and payload.params.message.context_id
|
|
86
|
+
):
|
|
89
87
|
context_id = payload.params.message.context_id
|
|
90
88
|
if isinstance(context_id, str) and context_id.strip():
|
|
91
89
|
frontend_session_id = context_id.strip()
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
|
|
94
91
|
if frontend_session_id:
|
|
95
92
|
session_id = frontend_session_id
|
|
96
|
-
log.info(
|
|
93
|
+
log.info(
|
|
94
|
+
"%sUsing session ID from frontend request: %s", log_prefix, session_id
|
|
95
|
+
)
|
|
97
96
|
else:
|
|
98
97
|
# Create new session when frontend doesn't provide one (None, empty, or whitespace-only)
|
|
99
98
|
session_id = session_manager.create_new_session_id(request)
|
|
100
|
-
log.info(
|
|
99
|
+
log.info(
|
|
100
|
+
"%sNo valid session ID from frontend, created new session: %s",
|
|
101
|
+
log_prefix,
|
|
102
|
+
session_id,
|
|
103
|
+
)
|
|
101
104
|
|
|
102
105
|
log.info(
|
|
103
106
|
"%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
|
|
@@ -106,38 +109,24 @@ async def _submit_task(
|
|
|
106
109
|
# Store message in persistence layer if available
|
|
107
110
|
user_id = user_identity.get("id")
|
|
108
111
|
from ....gateway.http_sse.dependencies import SessionLocal
|
|
112
|
+
|
|
109
113
|
if is_streaming and SessionLocal is not None:
|
|
110
114
|
try:
|
|
111
|
-
from ....gateway.http_sse.dependencies import
|
|
115
|
+
from ....gateway.http_sse.dependencies import (
|
|
116
|
+
create_session_service_with_transaction,
|
|
117
|
+
)
|
|
112
118
|
from ....gateway.http_sse.shared.enums import SenderType
|
|
113
|
-
|
|
119
|
+
|
|
114
120
|
with create_session_service_with_transaction() as (session_service, db):
|
|
115
|
-
existing_session = session_service.get_session(session_id=session_id, user_id=user_id)
|
|
116
|
-
if not existing_session:
|
|
117
|
-
log.info("%sCreating new session in database: %s", log_prefix, session_id)
|
|
118
|
-
try:
|
|
119
|
-
session_service.create_session(
|
|
120
|
-
user_id=user_id,
|
|
121
|
-
agent_id=agent_name,
|
|
122
|
-
name=None,
|
|
123
|
-
session_id=session_id
|
|
124
|
-
)
|
|
125
|
-
except Exception as create_error:
|
|
126
|
-
log.warning("%sSession creation failed, checking if session exists: %s", log_prefix, create_error)
|
|
127
|
-
existing_session = session_service.get_session(session_id=session_id, user_id=user_id)
|
|
128
|
-
if not existing_session:
|
|
129
|
-
raise create_error
|
|
130
|
-
log.info("%sSession was created by another request: %s", log_prefix, session_id)
|
|
131
|
-
|
|
132
121
|
message_text = ""
|
|
133
122
|
if payload.params and payload.params.message:
|
|
134
123
|
parts = a2a.get_parts_from_message(payload.params.message)
|
|
135
124
|
for part in parts:
|
|
136
|
-
if hasattr(part,
|
|
125
|
+
if hasattr(part, "text"):
|
|
137
126
|
message_text = part.text
|
|
138
127
|
break
|
|
139
|
-
|
|
140
|
-
|
|
128
|
+
|
|
129
|
+
session_service.add_message_to_session(
|
|
141
130
|
session_id=session_id,
|
|
142
131
|
user_id=user_id,
|
|
143
132
|
message=message_text or "Task submitted",
|
|
@@ -145,15 +134,16 @@ async def _submit_task(
|
|
|
145
134
|
sender_name=user_id or "user",
|
|
146
135
|
agent_id=agent_name,
|
|
147
136
|
)
|
|
148
|
-
|
|
149
|
-
if message_domain:
|
|
150
|
-
log.info("%sMessage stored in session %s", log_prefix, session_id)
|
|
151
|
-
else:
|
|
152
|
-
log.warning("%sFailed to store message in session %s", log_prefix, session_id)
|
|
137
|
+
|
|
153
138
|
except Exception as e:
|
|
154
|
-
log.error(
|
|
139
|
+
log.error(
|
|
140
|
+
"%sFailed to store message in session service: %s", log_prefix, e
|
|
141
|
+
)
|
|
155
142
|
else:
|
|
156
|
-
log.debug(
|
|
143
|
+
log.debug(
|
|
144
|
+
"%sNo persistence available or non-streaming - skipping message storage",
|
|
145
|
+
log_prefix,
|
|
146
|
+
)
|
|
157
147
|
|
|
158
148
|
# Use the helper to get the unwrapped parts from the incoming message.
|
|
159
149
|
a2a_parts = a2a.get_parts_from_message(payload.params.message)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
from typing import TYPE_CHECKING
|
|
2
|
+
from typing import TYPE_CHECKING, Optional
|
|
3
3
|
|
|
4
4
|
from solace_ai_connector.common.log import log
|
|
5
5
|
|
|
@@ -29,6 +29,12 @@ class SessionService:
|
|
|
29
29
|
self.message_repository = message_repository
|
|
30
30
|
self.component = component
|
|
31
31
|
|
|
32
|
+
def is_persistence_enabled(self) -> bool:
|
|
33
|
+
"""Checks if the service is configured with a persistent backend."""
|
|
34
|
+
# The presence of a database_url on the component is the source of truth
|
|
35
|
+
# for whether SQL persistence is enabled.
|
|
36
|
+
return self.component and self.component.database_url is not None
|
|
37
|
+
|
|
32
38
|
def get_user_sessions(
|
|
33
39
|
self, user_id: UserId, pagination: PaginationInfo | None = None
|
|
34
40
|
) -> list[Session]:
|
|
@@ -73,7 +79,11 @@ class SessionService:
|
|
|
73
79
|
name: str | None = None,
|
|
74
80
|
agent_id: str | None = None,
|
|
75
81
|
session_id: str | None = None,
|
|
76
|
-
) -> Session:
|
|
82
|
+
) -> Optional[Session]:
|
|
83
|
+
if not self.is_persistence_enabled():
|
|
84
|
+
log.debug("Persistence is not enabled. Skipping session creation in DB.")
|
|
85
|
+
return None
|
|
86
|
+
|
|
77
87
|
if not user_id or user_id.strip() == "":
|
|
78
88
|
raise ValueError("User ID cannot be empty")
|
|
79
89
|
|
|
@@ -92,9 +102,15 @@ class SessionService:
|
|
|
92
102
|
updated_time=now_ms,
|
|
93
103
|
)
|
|
94
104
|
|
|
105
|
+
if not session:
|
|
106
|
+
raise ValueError(f"Failed to create session for {session_id}")
|
|
107
|
+
|
|
95
108
|
created_session = self.session_repository.save(session)
|
|
96
109
|
log.info("Created new session %s for user %s", created_session.id, user_id)
|
|
97
110
|
|
|
111
|
+
if not created_session:
|
|
112
|
+
raise ValueError(f"Failed to save session for {session_id}")
|
|
113
|
+
|
|
98
114
|
return created_session
|
|
99
115
|
|
|
100
116
|
def update_session_name(
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: solace-agent-mesh
|
|
3
|
-
Version: 1.4.
|
|
3
|
+
Version: 1.4.7
|
|
4
4
|
Summary: Solace Agent Mesh is an open-source framework for building event-driven, multi-agent AI systems where specialized agents collaborate on complex tasks.
|
|
5
5
|
Project-URL: Homepage, https://github.com/SolaceLabs/solace-agent-mesh
|
|
6
6
|
Project-URL: Repository, https://github.com/SolaceLabs/solace-agent-mesh
|