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
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
# DEVELOPER GUIDE: services
|
|
2
2
|
|
|
3
3
|
## Quick Summary
|
|
4
|
-
The `services` directory contains the business logic layer for the HTTP SSE Gateway. It provides high-level services for agent management (discovering and retrieving A2A agents), user
|
|
4
|
+
The `services` directory contains the business logic layer for the HTTP SSE Gateway. It provides high-level services for agent management (discovering and retrieving A2A agents), user feedback processing with database persistence and event publishing, user search via identity services, session management with database persistence, task logging to database, data retention/cleanup, and A2A task operations like cancellation.
|
|
5
5
|
|
|
6
6
|
## Files Overview
|
|
7
7
|
- `__init__.py` - Package initialization file marking the directory as a Python package
|
|
8
|
-
- `
|
|
8
|
+
- `agent_card_service.py` - Service for retrieving information about discovered A2A agents from the registry
|
|
9
|
+
- `data_retention_service.py` - Service for automatic cleanup of old tasks and feedback based on retention policies
|
|
10
|
+
- `feedback_service.py` - Service for processing and storing user feedback on chat messages with database and event publishing
|
|
9
11
|
- `people_service.py` - Service for searching users via configured identity services
|
|
10
|
-
- `
|
|
12
|
+
- `session_service.py` - Service for managing chat sessions and messages with database persistence
|
|
13
|
+
- `task_logger_service.py` - Service for logging A2A tasks and events to the database
|
|
14
|
+
- `task_service.py` - Service for handling A2A task operations like cancellation
|
|
11
15
|
|
|
12
16
|
## Developer API Reference
|
|
13
17
|
|
|
@@ -15,36 +19,107 @@ The `services` directory contains the business logic layer for the HTTP SSE Gate
|
|
|
15
19
|
**Purpose:** Marks the services directory as a Python package
|
|
16
20
|
**Import:** N/A - No public interfaces
|
|
17
21
|
|
|
18
|
-
###
|
|
22
|
+
### agent_card_service.py
|
|
19
23
|
**Purpose:** Provides methods for accessing information about discovered A2A agents from the shared AgentRegistry
|
|
20
|
-
**Import:** `from solace_agent_mesh.gateway.http_sse.services.
|
|
24
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.services.agent_card_service import AgentCardService`
|
|
21
25
|
|
|
22
26
|
**Classes:**
|
|
23
|
-
- `
|
|
24
|
-
- `
|
|
25
|
-
- `
|
|
27
|
+
- `AgentCardService(agent_registry: AgentRegistry)` - Service for accessing discovered A2A agent information
|
|
28
|
+
- `get_all_agent_cards() -> List[AgentCard]` - Retrieves all currently discovered and registered agent cards
|
|
29
|
+
- `get_agent_card_by_name(agent_name: str) -> Optional[AgentCard]` - Retrieves a specific agent card by name, returns None if not found
|
|
26
30
|
|
|
27
31
|
**Usage Examples:**
|
|
28
32
|
```python
|
|
29
|
-
from solace_agent_mesh.gateway.http_sse.services.
|
|
33
|
+
from solace_agent_mesh.gateway.http_sse.services.agent_card_service import AgentCardService
|
|
30
34
|
from solace_agent_mesh.common.agent_registry import AgentRegistry
|
|
31
35
|
|
|
32
36
|
# Initialize with shared agent registry
|
|
33
37
|
agent_registry = AgentRegistry() # Usually injected as shared instance
|
|
34
|
-
agent_service =
|
|
38
|
+
agent_service = AgentCardService(agent_registry=agent_registry)
|
|
35
39
|
|
|
36
40
|
# Get all available agents
|
|
37
|
-
all_agents = agent_service.
|
|
41
|
+
all_agents = agent_service.get_all_agent_cards()
|
|
38
42
|
print(f"Found {len(all_agents)} agents")
|
|
39
43
|
|
|
40
44
|
# Get specific agent by name
|
|
41
|
-
agent = agent_service.
|
|
45
|
+
agent = agent_service.get_agent_card_by_name("data-processor")
|
|
42
46
|
if agent:
|
|
43
47
|
print(f"Found agent: {agent.name}")
|
|
44
48
|
else:
|
|
45
49
|
print("Agent not found")
|
|
46
50
|
```
|
|
47
51
|
|
|
52
|
+
### data_retention_service.py
|
|
53
|
+
**Purpose:** Service for automatically cleaning up old tasks, task events, and feedback based on configurable retention policies
|
|
54
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.services.data_retention_service import DataRetentionService`
|
|
55
|
+
|
|
56
|
+
**Classes:**
|
|
57
|
+
- `DataRetentionService(session_factory: Callable[[], DBSession] | None, config: Dict[str, Any])` - Service for automatic data cleanup based on retention policies
|
|
58
|
+
- `cleanup_old_data() -> None` - Main orchestration method for cleaning up old data, calls cleanup methods for tasks and feedback
|
|
59
|
+
|
|
60
|
+
**Constants/Variables:**
|
|
61
|
+
- `MIN_RETENTION_DAYS: int` - Minimum retention period (7 days)
|
|
62
|
+
- `MIN_CLEANUP_INTERVAL_HOURS: int` - Minimum cleanup interval (1 hour)
|
|
63
|
+
- `MIN_BATCH_SIZE: int` - Minimum batch size for deletion (1)
|
|
64
|
+
- `MAX_BATCH_SIZE: int` - Maximum batch size for deletion (10000)
|
|
65
|
+
|
|
66
|
+
**Usage Examples:**
|
|
67
|
+
```python
|
|
68
|
+
from solace_agent_mesh.gateway.http_sse.services.data_retention_service import DataRetentionService
|
|
69
|
+
from sqlalchemy.orm import sessionmaker
|
|
70
|
+
|
|
71
|
+
# Initialize with database session factory and config
|
|
72
|
+
session_factory = sessionmaker(bind=your_engine)
|
|
73
|
+
config = {
|
|
74
|
+
"enabled": True,
|
|
75
|
+
"task_retention_days": 90,
|
|
76
|
+
"feedback_retention_days": 90,
|
|
77
|
+
"cleanup_interval_hours": 24,
|
|
78
|
+
"batch_size": 1000
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
retention_service = DataRetentionService(
|
|
82
|
+
session_factory=session_factory,
|
|
83
|
+
config=config
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Run cleanup (typically called by scheduler)
|
|
87
|
+
retention_service.cleanup_old_data()
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### feedback_service.py
|
|
91
|
+
**Purpose:** Handles the business logic for processing and storing user feedback with database persistence and event publishing
|
|
92
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.services.feedback_service import FeedbackService`
|
|
93
|
+
|
|
94
|
+
**Classes:**
|
|
95
|
+
- `FeedbackService(session_factory: Callable[[], DBSession] | None, component: WebUIBackendComponent, task_repo: ITaskRepository)` - Service for processing user feedback with database persistence and event publishing
|
|
96
|
+
- `process_feedback(payload: FeedbackPayload, user_id: str) -> None` - Asynchronously processes and stores feedback, publishes events if configured
|
|
97
|
+
|
|
98
|
+
**Usage Examples:**
|
|
99
|
+
```python
|
|
100
|
+
import asyncio
|
|
101
|
+
from solace_agent_mesh.gateway.http_sse.services.feedback_service import FeedbackService
|
|
102
|
+
from sqlalchemy.orm import sessionmaker
|
|
103
|
+
|
|
104
|
+
# Initialize with database session factory
|
|
105
|
+
session_factory = sessionmaker(bind=your_engine)
|
|
106
|
+
component = YourWebUIBackendComponent() # Your component instance
|
|
107
|
+
task_repo = YourTaskRepository() # Your task repository
|
|
108
|
+
|
|
109
|
+
feedback_service = FeedbackService(
|
|
110
|
+
session_factory=session_factory,
|
|
111
|
+
component=component,
|
|
112
|
+
task_repo=task_repo
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
# Process feedback (requires FeedbackPayload from router)
|
|
116
|
+
async def process_user_feedback():
|
|
117
|
+
# payload would be a FeedbackPayload instance from the router
|
|
118
|
+
await feedback_service.process_feedback(payload, user_id="user123")
|
|
119
|
+
|
|
120
|
+
asyncio.run(process_user_feedback())
|
|
121
|
+
```
|
|
122
|
+
|
|
48
123
|
### people_service.py
|
|
49
124
|
**Purpose:** Provides user search functionality via configured identity services
|
|
50
125
|
**Import:** `from solace_agent_mesh.gateway.http_sse.services.people_service import PeopleService`
|
|
@@ -76,6 +151,95 @@ people_service_no_id = PeopleService(identity_service=None)
|
|
|
76
151
|
asyncio.run(search_users())
|
|
77
152
|
```
|
|
78
153
|
|
|
154
|
+
### session_service.py
|
|
155
|
+
**Purpose:** Manages chat sessions and messages with database persistence support
|
|
156
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.services.session_service import SessionService`
|
|
157
|
+
|
|
158
|
+
**Classes:**
|
|
159
|
+
- `SessionService(component: WebUIBackendComponent = None)` - Service for managing chat sessions and messages
|
|
160
|
+
- `is_persistence_enabled() -> bool` - Checks if the service is configured with a persistent backend
|
|
161
|
+
- `get_user_sessions(db: DbSession, user_id: UserId, pagination: PaginationParams | None = None) -> PaginatedResponse[Session]` - Retrieves paginated sessions for a user
|
|
162
|
+
- `get_session_details(db: DbSession, session_id: SessionId, user_id: UserId) -> Session | None` - Gets session details for a specific session
|
|
163
|
+
- `get_session_history(db: DbSession, session_id: SessionId, user_id: UserId, pagination: PaginationInfo | None = None) -> SessionHistory | None` - Gets session with messages
|
|
164
|
+
- `create_session(db: DbSession, user_id: UserId, name: str | None = None, agent_id: str | None = None, session_id: str | None = None) -> Optional[Session]` - Creates a new session
|
|
165
|
+
- `update_session_name(db: DbSession, session_id: SessionId, user_id: UserId, name: str) -> Session | None` - Updates session name
|
|
166
|
+
- `delete_session_with_notifications(db: DbSession, session_id: SessionId, user_id: UserId) -> bool` - Deletes session and notifies agents
|
|
167
|
+
- `add_message_to_session(db: DbSession, session_id: SessionId, user_id: UserId, message: str, sender_type: SenderType, sender_name: str, agent_id: str | None = None, message_type: MessageType = MessageType.TEXT) -> Message` - Adds a message to a session
|
|
168
|
+
|
|
169
|
+
**Usage Examples:**
|
|
170
|
+
```python
|
|
171
|
+
from solace_agent_mesh.gateway.http_sse.services.session_service import SessionService
|
|
172
|
+
from solace_agent_mesh.gateway.http_sse.shared.enums import SenderType, MessageType
|
|
173
|
+
from sqlalchemy.orm import Session as DbSession
|
|
174
|
+
|
|
175
|
+
# Initialize with component
|
|
176
|
+
component = YourWebUIBackendComponent() # Your component
|
|
177
|
+
session_service = SessionService(component=component)
|
|
178
|
+
|
|
179
|
+
# Use with database session
|
|
180
|
+
with your_session_factory() as db:
|
|
181
|
+
# Create a new session
|
|
182
|
+
session = session_service.create_session(
|
|
183
|
+
db=db,
|
|
184
|
+
user_id="user123",
|
|
185
|
+
name="My Chat Session",
|
|
186
|
+
agent_id="assistant-agent"
|
|
187
|
+
)
|
|
188
|
+
|
|
189
|
+
# Add a message to the session
|
|
190
|
+
message = session_service.add_message_to_session(
|
|
191
|
+
db=db,
|
|
192
|
+
session_id=session.id,
|
|
193
|
+
user_id="user123",
|
|
194
|
+
message="Hello, how can you help me?",
|
|
195
|
+
sender_type=SenderType.USER,
|
|
196
|
+
sender_name="John Doe"
|
|
197
|
+
)
|
|
198
|
+
|
|
199
|
+
# Get user's sessions with pagination
|
|
200
|
+
paginated_sessions = session_service.get_user_sessions(db, "user123")
|
|
201
|
+
|
|
202
|
+
db.commit()
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### task_logger_service.py
|
|
206
|
+
**Purpose:** Service for logging A2A tasks and events to the database with configurable filtering and sanitization
|
|
207
|
+
**Import:** `from solace_agent_mesh.gateway.http_sse.services.task_logger_service import TaskLoggerService`
|
|
208
|
+
|
|
209
|
+
**Classes:**
|
|
210
|
+
- `TaskLoggerService(session_factory: Callable[[], DBSession] | None, config: Dict[str, Any])` - Service for logging A2A tasks and events to database
|
|
211
|
+
- `log_event(event_data: Dict[str, Any]) -> None` - Parses a raw A2A message and logs it as a task event, creates or updates master task record
|
|
212
|
+
|
|
213
|
+
**Usage Examples:**
|
|
214
|
+
```python
|
|
215
|
+
from solace_agent_mesh.gateway.http_sse.services.task_logger_service import TaskLoggerService
|
|
216
|
+
from sqlalchemy.orm import sessionmaker
|
|
217
|
+
|
|
218
|
+
# Initialize with database session factory and config
|
|
219
|
+
session_factory = sessionmaker(bind=your_engine)
|
|
220
|
+
config = {
|
|
221
|
+
"enabled": True,
|
|
222
|
+
"log_status_updates": True,
|
|
223
|
+
"log_artifact_events": False,
|
|
224
|
+
"log_file_parts": True,
|
|
225
|
+
"max_file_part_size_bytes": 102400
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
task_logger = TaskLoggerService(
|
|
229
|
+
session_factory=session_factory,
|
|
230
|
+
config=config
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
# Log an A2A event
|
|
234
|
+
event_data = {
|
|
235
|
+
"topic": "sam/agents/my-agent/request",
|
|
236
|
+
"payload": {"id": "task-123", "method": "sendMessage"},
|
|
237
|
+
"user_properties": {"userId": "user@example.com"}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
task_logger.log_event(event_data)
|
|
241
|
+
```
|
|
242
|
+
|
|
79
243
|
### task_service.py
|
|
80
244
|
**Purpose:** Handles A2A task operations, specifically task cancellation using CoreA2AService and message publishing
|
|
81
245
|
**Import:** `from solace_agent_mesh.gateway.http_sse.services.task_service import TaskService, PublishFunc`
|
|
@@ -130,4 +294,4 @@ async def cancel_task_example():
|
|
|
130
294
|
asyncio.run(cancel_task_example())
|
|
131
295
|
```
|
|
132
296
|
|
|
133
|
-
# content_hash:
|
|
297
|
+
# content_hash: 12385f5117d2f5c30f0e44a0913ea91d62722aa82eb55268ae6bd317311ec5eb
|
|
@@ -1,18 +1,17 @@
|
|
|
1
1
|
import uuid
|
|
2
|
-
from typing import TYPE_CHECKING, Optional
|
|
2
|
+
from typing import TYPE_CHECKING, Optional, List, Dict, Any
|
|
3
3
|
|
|
4
4
|
from solace_ai_connector.common.log import log
|
|
5
5
|
from sqlalchemy.orm import Session as DbSession
|
|
6
6
|
|
|
7
7
|
from ..repository import (
|
|
8
|
-
IMessageRepository,
|
|
9
8
|
ISessionRepository,
|
|
10
|
-
Message,
|
|
11
9
|
Session,
|
|
12
|
-
SessionHistory,
|
|
13
10
|
)
|
|
14
|
-
from ..
|
|
15
|
-
from ..
|
|
11
|
+
from ..repository.chat_task_repository import ChatTaskRepository
|
|
12
|
+
from ..repository.entities import ChatTask
|
|
13
|
+
from ..shared.enums import SenderType
|
|
14
|
+
from ..shared.types import SessionId, UserId
|
|
16
15
|
from ..shared import now_epoch_ms
|
|
17
16
|
from ..shared.pagination import PaginationParams, PaginatedResponse, get_pagination_or_default
|
|
18
17
|
|
|
@@ -28,11 +27,10 @@ class SessionService:
|
|
|
28
27
|
self.component = component
|
|
29
28
|
|
|
30
29
|
def _get_repositories(self, db: DbSession):
|
|
31
|
-
"""Create
|
|
32
|
-
from ..repository import SessionRepository
|
|
30
|
+
"""Create session repository for the given database session."""
|
|
31
|
+
from ..repository import SessionRepository
|
|
33
32
|
session_repository = SessionRepository(db)
|
|
34
|
-
|
|
35
|
-
return session_repository, message_repository
|
|
33
|
+
return session_repository
|
|
36
34
|
|
|
37
35
|
def is_persistence_enabled(self) -> bool:
|
|
38
36
|
"""Checks if the service is configured with a persistent backend."""
|
|
@@ -54,18 +52,10 @@ class SessionService:
|
|
|
54
52
|
raise ValueError("User ID cannot be empty")
|
|
55
53
|
|
|
56
54
|
pagination = get_pagination_or_default(pagination)
|
|
57
|
-
session_repository
|
|
58
|
-
|
|
59
|
-
pagination_info = PaginationInfo(
|
|
60
|
-
page=pagination.page_number,
|
|
61
|
-
page_size=pagination.page_size,
|
|
62
|
-
total_items=0,
|
|
63
|
-
total_pages=0,
|
|
64
|
-
has_next=False,
|
|
65
|
-
has_previous=False,
|
|
66
|
-
)
|
|
55
|
+
session_repository = self._get_repositories(db)
|
|
67
56
|
|
|
68
|
-
|
|
57
|
+
# Pass pagination params directly - repository will handle offset calculation
|
|
58
|
+
sessions = session_repository.find_by_user(user_id, pagination)
|
|
69
59
|
total_count = session_repository.count_by_user(user_id)
|
|
70
60
|
|
|
71
61
|
return PaginatedResponse.create(sessions, total_count, pagination)
|
|
@@ -76,33 +66,9 @@ class SessionService:
|
|
|
76
66
|
if not self._is_valid_session_id(session_id):
|
|
77
67
|
return None
|
|
78
68
|
|
|
79
|
-
session_repository
|
|
69
|
+
session_repository = self._get_repositories(db)
|
|
80
70
|
return session_repository.find_user_session(session_id, user_id)
|
|
81
71
|
|
|
82
|
-
def get_session_history(
|
|
83
|
-
self,
|
|
84
|
-
db: DbSession,
|
|
85
|
-
session_id: SessionId,
|
|
86
|
-
user_id: UserId,
|
|
87
|
-
pagination: PaginationInfo | None = None,
|
|
88
|
-
) -> SessionHistory | None:
|
|
89
|
-
if not self._is_valid_session_id(session_id):
|
|
90
|
-
return None
|
|
91
|
-
|
|
92
|
-
session_repository, _ = self._get_repositories(db)
|
|
93
|
-
result = session_repository.find_user_session_with_messages(
|
|
94
|
-
session_id, user_id, pagination
|
|
95
|
-
)
|
|
96
|
-
if not result:
|
|
97
|
-
return None
|
|
98
|
-
|
|
99
|
-
session, messages = result
|
|
100
|
-
return SessionHistory(
|
|
101
|
-
session=session,
|
|
102
|
-
messages=messages,
|
|
103
|
-
total_message_count=len(messages),
|
|
104
|
-
)
|
|
105
|
-
|
|
106
72
|
def create_session(
|
|
107
73
|
self,
|
|
108
74
|
db: DbSession,
|
|
@@ -131,7 +97,7 @@ class SessionService:
|
|
|
131
97
|
updated_time=now_ms,
|
|
132
98
|
)
|
|
133
99
|
|
|
134
|
-
session_repository
|
|
100
|
+
session_repository = self._get_repositories(db)
|
|
135
101
|
created_session = session_repository.save(session)
|
|
136
102
|
log.info("Created new session %s for user %s", created_session.id, user_id)
|
|
137
103
|
|
|
@@ -152,7 +118,7 @@ class SessionService:
|
|
|
152
118
|
if len(name.strip()) > 255:
|
|
153
119
|
raise ValueError("Session name cannot exceed 255 characters")
|
|
154
120
|
|
|
155
|
-
session_repository
|
|
121
|
+
session_repository = self._get_repositories(db)
|
|
156
122
|
session = session_repository.find_user_session(session_id, user_id)
|
|
157
123
|
if not session:
|
|
158
124
|
return None
|
|
@@ -169,7 +135,7 @@ class SessionService:
|
|
|
169
135
|
if not self._is_valid_session_id(session_id):
|
|
170
136
|
raise ValueError("Invalid session ID")
|
|
171
137
|
|
|
172
|
-
session_repository
|
|
138
|
+
session_repository = self._get_repositories(db)
|
|
173
139
|
session = session_repository.find_user_session(session_id, user_id)
|
|
174
140
|
if not session:
|
|
175
141
|
log.warning(
|
|
@@ -198,50 +164,151 @@ class SessionService:
|
|
|
198
164
|
|
|
199
165
|
return True
|
|
200
166
|
|
|
201
|
-
def
|
|
167
|
+
def save_task(
|
|
202
168
|
self,
|
|
203
169
|
db: DbSession,
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
170
|
+
task_id: str,
|
|
171
|
+
session_id: str,
|
|
172
|
+
user_id: str,
|
|
173
|
+
user_message: Optional[str],
|
|
174
|
+
message_bubbles: str, # JSON string (opaque)
|
|
175
|
+
task_metadata: Optional[str] = None # JSON string (opaque)
|
|
176
|
+
) -> ChatTask:
|
|
177
|
+
"""
|
|
178
|
+
Save a complete task interaction.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
db: Database session
|
|
182
|
+
task_id: A2A task ID
|
|
183
|
+
session_id: Session ID
|
|
184
|
+
user_id: User ID
|
|
185
|
+
user_message: Original user input text
|
|
186
|
+
message_bubbles: Array of all message bubbles displayed during this task
|
|
187
|
+
task_metadata: Task-level metadata (status, feedback, agent name, etc.)
|
|
188
|
+
|
|
189
|
+
Returns:
|
|
190
|
+
Saved ChatTask entity
|
|
191
|
+
|
|
192
|
+
Raises:
|
|
193
|
+
ValueError: If session not found or validation fails
|
|
194
|
+
"""
|
|
195
|
+
# Validate session exists and belongs to user
|
|
196
|
+
session_repository = self._get_repositories(db)
|
|
219
197
|
session = session_repository.find_user_session(session_id, user_id)
|
|
220
198
|
if not session:
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
)
|
|
227
|
-
|
|
228
|
-
message_entity = Message(
|
|
229
|
-
id=str(uuid.uuid4()),
|
|
199
|
+
raise ValueError(f"Session {session_id} not found for user {user_id}")
|
|
200
|
+
|
|
201
|
+
# Create task entity - pass strings directly
|
|
202
|
+
task = ChatTask(
|
|
203
|
+
id=task_id,
|
|
230
204
|
session_id=session_id,
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
205
|
+
user_id=user_id,
|
|
206
|
+
user_message=user_message,
|
|
207
|
+
message_bubbles=message_bubbles, # Already a string
|
|
208
|
+
task_metadata=task_metadata, # Already a string
|
|
235
209
|
created_time=now_epoch_ms(),
|
|
210
|
+
updated_time=None
|
|
236
211
|
)
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
212
|
+
|
|
213
|
+
# Save via repository
|
|
214
|
+
task_repo = ChatTaskRepository(db)
|
|
215
|
+
saved_task = task_repo.save(task)
|
|
216
|
+
|
|
217
|
+
# Update session activity
|
|
240
218
|
session.mark_activity()
|
|
241
219
|
session_repository.save(session)
|
|
220
|
+
|
|
221
|
+
log.info(f"Saved task {task_id} for session {session_id}")
|
|
222
|
+
return saved_task
|
|
242
223
|
|
|
243
|
-
|
|
244
|
-
|
|
224
|
+
def get_session_tasks(
|
|
225
|
+
self,
|
|
226
|
+
db: DbSession,
|
|
227
|
+
session_id: str,
|
|
228
|
+
user_id: str
|
|
229
|
+
) -> List[ChatTask]:
|
|
230
|
+
"""
|
|
231
|
+
Get all tasks for a session.
|
|
232
|
+
|
|
233
|
+
Args:
|
|
234
|
+
db: Database session
|
|
235
|
+
session_id: Session ID
|
|
236
|
+
user_id: User ID
|
|
237
|
+
|
|
238
|
+
Returns:
|
|
239
|
+
List of ChatTask entities in chronological order
|
|
240
|
+
|
|
241
|
+
Raises:
|
|
242
|
+
ValueError: If session not found
|
|
243
|
+
"""
|
|
244
|
+
# Validate session exists and belongs to user
|
|
245
|
+
session_repository = self._get_repositories(db)
|
|
246
|
+
session = session_repository.find_user_session(session_id, user_id)
|
|
247
|
+
if not session:
|
|
248
|
+
raise ValueError(f"Session {session_id} not found for user {user_id}")
|
|
249
|
+
|
|
250
|
+
# Load tasks
|
|
251
|
+
task_repo = ChatTaskRepository(db)
|
|
252
|
+
return task_repo.find_by_session(session_id, user_id)
|
|
253
|
+
|
|
254
|
+
def get_session_messages_from_tasks(
|
|
255
|
+
self,
|
|
256
|
+
db: DbSession,
|
|
257
|
+
session_id: str,
|
|
258
|
+
user_id: str
|
|
259
|
+
) -> List[Dict[str, Any]]:
|
|
260
|
+
"""
|
|
261
|
+
Get session messages by flattening task message_bubbles.
|
|
262
|
+
This provides backward compatibility with the old message-based API.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
db: Database session
|
|
266
|
+
session_id: Session ID
|
|
267
|
+
user_id: User ID
|
|
268
|
+
|
|
269
|
+
Returns:
|
|
270
|
+
List of message dictionaries flattened from tasks
|
|
271
|
+
|
|
272
|
+
Raises:
|
|
273
|
+
ValueError: If session not found
|
|
274
|
+
"""
|
|
275
|
+
# Load tasks
|
|
276
|
+
tasks = self.get_session_tasks(db, session_id, user_id)
|
|
277
|
+
|
|
278
|
+
# Flatten message_bubbles from all tasks
|
|
279
|
+
messages = []
|
|
280
|
+
for task in tasks:
|
|
281
|
+
import json
|
|
282
|
+
message_bubbles = json.loads(task.message_bubbles) if isinstance(task.message_bubbles, str) else task.message_bubbles
|
|
283
|
+
|
|
284
|
+
for bubble in message_bubbles:
|
|
285
|
+
# Determine sender type from bubble type
|
|
286
|
+
bubble_type = bubble.get("type", "agent")
|
|
287
|
+
sender_type = "user" if bubble_type == "user" else "agent"
|
|
288
|
+
|
|
289
|
+
# Get sender name
|
|
290
|
+
if bubble_type == "user":
|
|
291
|
+
sender_name = user_id
|
|
292
|
+
else:
|
|
293
|
+
# Try to get agent name from task metadata, fallback to "agent"
|
|
294
|
+
sender_name = "agent"
|
|
295
|
+
if task.task_metadata:
|
|
296
|
+
task_metadata = json.loads(task.task_metadata) if isinstance(task.task_metadata, str) else task.task_metadata
|
|
297
|
+
sender_name = task_metadata.get("agent_name", "agent")
|
|
298
|
+
|
|
299
|
+
# Create message dictionary
|
|
300
|
+
message = {
|
|
301
|
+
"id": bubble.get("id", str(uuid.uuid4())),
|
|
302
|
+
"session_id": session_id,
|
|
303
|
+
"message": bubble.get("text", ""),
|
|
304
|
+
"sender_type": sender_type,
|
|
305
|
+
"sender_name": sender_name,
|
|
306
|
+
"message_type": "text",
|
|
307
|
+
"created_time": task.created_time
|
|
308
|
+
}
|
|
309
|
+
messages.append(message)
|
|
310
|
+
|
|
311
|
+
return messages
|
|
245
312
|
|
|
246
313
|
def _is_valid_session_id(self, session_id: SessionId) -> bool:
|
|
247
314
|
return (
|
|
@@ -289,4 +356,4 @@ class SessionService:
|
|
|
289
356
|
"Failed to publish session deletion event to agent %s: %s",
|
|
290
357
|
agent_id,
|
|
291
358
|
e,
|
|
292
|
-
)
|
|
359
|
+
)
|