solace-agent-mesh 1.3.1__py3-none-any.whl → 1.3.3__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/artifacts/filesystem_artifact_service.py +16 -8
- solace_agent_mesh/agent/protocol/event_handlers.py +91 -0
- solace_agent_mesh/agent/sac/app.py +2 -0
- solace_agent_mesh/assets/docs/404.html +3 -3
- solace_agent_mesh/assets/docs/assets/js/0e682baa.da822665.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1023fc19.8a8a9309.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.2645ef68.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.43771adc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.2afaee76.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/332e10b5.f7629851.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/3d406171.5560fdf9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.3f34bf76.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/442a8107.b5c2532a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/483cef9a.8d318c2f.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/55f47984.bcd00a86.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.dff11eca.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/664b740a.ba305a89.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/75384d09.abdf9cf9.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/768e31b0.9abcdc48.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/945fb41e.abf2be91.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.5a319fd4.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.d62aad71.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.1d029b81.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{aba87c2f.071e2d94.js → aba87c2f.4ddf32f2.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.abca774a.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/ae4415af.24cdc514.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/bac0be12.27ee2c26.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c2c06897.87cb1f47.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/c835a94d.ce21f0bf.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cc969b05.feef7dcc.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.a19e7d78.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{cee5d587.f5b73ca1.js → cee5d587.f1e1ca86.js} +1 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.cad4dbf2.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/f897a61a.bc634a3e.js +1 -0
- solace_agent_mesh/assets/docs/assets/js/{main.1c79039d.js → main.e82b32e6.js} +2 -2
- solace_agent_mesh/assets/docs/assets/js/runtime~main.aad1f874.js +1 -0
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +4 -4
- solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/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/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 +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +18 -18
- 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 +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
- 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 +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +3 -3
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +23 -23
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +5 -5
- 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 +9 -9
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +10 -10
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +8 -8
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +6 -6
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +9 -9
- 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 +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +5 -5
- 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 +5 -5
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +18 -18
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +7 -7
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +8 -8
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +10 -10
- 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 +4 -4
- solace_agent_mesh/assets/docs/lunr-index-1757873594308.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757873594308.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/{main-C1k9E0aC.js → main-DjoMeldu.js} +8 -8
- solace_agent_mesh/client/webui/frontend/static/index.html +1 -1
- solace_agent_mesh/common/a2a/__init__.py +4 -0
- solace_agent_mesh/common/a2a/protocol.py +20 -0
- solace_agent_mesh/common/sac/sam_component_base.py +29 -9
- solace_agent_mesh/common/sam_events/__init__.py +9 -0
- solace_agent_mesh/common/sam_events/event_service.py +207 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +1 -1
- solace_agent_mesh/gateway/http_sse/component.py +45 -35
- solace_agent_mesh/gateway/http_sse/dependencies.py +123 -60
- solace_agent_mesh/gateway/http_sse/main.py +20 -33
- solace_agent_mesh/gateway/http_sse/repository/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/message.py +41 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session.py +45 -0
- solace_agent_mesh/gateway/http_sse/repository/entities/session_history.py +16 -0
- solace_agent_mesh/gateway/http_sse/repository/interfaces.py +64 -0
- solace_agent_mesh/gateway/http_sse/repository/message_repository.py +78 -0
- solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/repository/models/base.py +7 -0
- solace_agent_mesh/gateway/http_sse/repository/models/message_model.py +27 -0
- solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +27 -0
- solace_agent_mesh/gateway/http_sse/repository/session_repository.py +139 -0
- solace_agent_mesh/gateway/http_sse/routers/config.py +1 -0
- solace_agent_mesh/gateway/http_sse/routers/dto/requests/__init__.py +20 -0
- solace_agent_mesh/gateway/http_sse/{api → routers}/dto/requests/session_requests.py +1 -8
- solace_agent_mesh/gateway/http_sse/routers/dto/responses/__init__.py +16 -0
- solace_agent_mesh/gateway/http_sse/{api → routers}/dto/responses/session_responses.py +3 -30
- solace_agent_mesh/gateway/http_sse/{api/controllers/session_controller.py → routers/sessions.py} +20 -77
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +42 -49
- solace_agent_mesh/gateway/http_sse/{api/controllers/user_controller.py → routers/users.py} +1 -1
- solace_agent_mesh/gateway/http_sse/services/session_service.py +245 -0
- solace_agent_mesh/gateway/http_sse/session_manager.py +0 -3
- solace_agent_mesh/gateway/http_sse/shared/enums.py +0 -5
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/METADATA +1 -1
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/RECORD +120 -128
- solace_agent_mesh/assets/docs/assets/js/0e682baa.b3bbde9a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1023fc19.364235d5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1523c6b4.1b0ec6f9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/1c6e87d2.a8c5ce5a.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/2a9cab12.8909df92.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/332e10b5.7a103f42.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/3d406171.0b9eeed1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/442a8107.b3159bb2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/483cef9a.4e972867.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/5b4258a4.0d080cd9.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/768e31b0.8b51cd70.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/945fb41e.c63791d1.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/9eff14a2.472b0310.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/a3a92b25.4b7fa6a2.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/ae4415af.7a2f0bbf.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/bac0be12.f50d9bac.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c2c06897.587b4af5.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cc969b05.bd3e0d6c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/cd3d4052.b6535013.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/f897a61a.0aa29dbb.js +0 -1
- solace_agent_mesh/assets/docs/assets/js/runtime~main.858117b7.js +0 -1
- solace_agent_mesh/assets/docs/lunr-index-1757531604543.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1757531604543.json +0 -1
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +0 -676
- solace_agent_mesh/gateway/http_sse/api/__init__.py +0 -11
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +0 -9
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +0 -279
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +0 -37
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +0 -66
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +0 -43
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +0 -74
- solace_agent_mesh/gateway/http_sse/application/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +0 -135
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +0 -90
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +0 -54
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +0 -4
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +0 -123
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +0 -4
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +0 -16
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +0 -119
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +0 -31
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +0 -12
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +0 -3
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +0 -174
- /solace_agent_mesh/assets/docs/assets/js/{main.1c79039d.js.LICENSE.txt → main.e82b32e6.js.LICENSE.txt} +0 -0
- /solace_agent_mesh/gateway/http_sse/{api → routers}/dto/__init__.py +0 -0
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.3.1.dist-info → solace_agent_mesh-1.3.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Message SQLAlchemy model.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from sqlalchemy import Column, DateTime, ForeignKey, String, Text
|
|
6
|
+
from sqlalchemy.orm import relationship
|
|
7
|
+
from sqlalchemy.sql import func
|
|
8
|
+
|
|
9
|
+
from .base import Base
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class MessageModel(Base):
|
|
13
|
+
"""SQLAlchemy model for messages."""
|
|
14
|
+
|
|
15
|
+
__tablename__ = "chat_messages"
|
|
16
|
+
|
|
17
|
+
id = Column(String, primary_key=True)
|
|
18
|
+
session_id = Column(
|
|
19
|
+
String, ForeignKey("sessions.id", ondelete="CASCADE"), nullable=False
|
|
20
|
+
)
|
|
21
|
+
message = Column(Text, nullable=False)
|
|
22
|
+
created_at = Column(DateTime, default=func.now())
|
|
23
|
+
sender_type = Column(String(50))
|
|
24
|
+
sender_name = Column(String(255))
|
|
25
|
+
|
|
26
|
+
# Relationship to session
|
|
27
|
+
session = relationship("SessionModel", back_populates="messages")
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Session SQLAlchemy model.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from sqlalchemy import Column, DateTime, String
|
|
6
|
+
from sqlalchemy.orm import relationship
|
|
7
|
+
from sqlalchemy.sql import func
|
|
8
|
+
|
|
9
|
+
from .base import Base
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class SessionModel(Base):
|
|
13
|
+
"""SQLAlchemy model for sessions."""
|
|
14
|
+
|
|
15
|
+
__tablename__ = "sessions"
|
|
16
|
+
|
|
17
|
+
id = Column(String, primary_key=True)
|
|
18
|
+
name = Column(String, nullable=True)
|
|
19
|
+
user_id = Column(String, nullable=False)
|
|
20
|
+
agent_id = Column(String, nullable=True)
|
|
21
|
+
created_at = Column(DateTime, default=func.now())
|
|
22
|
+
updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
|
|
23
|
+
|
|
24
|
+
# Relationship to messages
|
|
25
|
+
messages = relationship(
|
|
26
|
+
"MessageModel", back_populates="session", cascade="all, delete-orphan"
|
|
27
|
+
)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Session repository implementation using SQLAlchemy.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from sqlalchemy.orm import Session as DBSession
|
|
6
|
+
|
|
7
|
+
from ..shared.types import PaginationInfo, SessionId, UserId
|
|
8
|
+
from .entities import Message, Session
|
|
9
|
+
from .interfaces import ISessionRepository
|
|
10
|
+
from .models import MessageModel, SessionModel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class SessionRepository(ISessionRepository):
|
|
14
|
+
"""SQLAlchemy implementation of session repository."""
|
|
15
|
+
|
|
16
|
+
def __init__(self, db: DBSession):
|
|
17
|
+
self.db = db
|
|
18
|
+
|
|
19
|
+
def find_by_user(
|
|
20
|
+
self, user_id: UserId, pagination: PaginationInfo | None = None
|
|
21
|
+
) -> list[Session]:
|
|
22
|
+
"""Find all sessions for a specific user."""
|
|
23
|
+
query = self.db.query(SessionModel).filter(SessionModel.user_id == user_id)
|
|
24
|
+
|
|
25
|
+
if pagination:
|
|
26
|
+
offset = (pagination.page - 1) * pagination.page_size
|
|
27
|
+
query = query.offset(offset).limit(pagination.page_size)
|
|
28
|
+
|
|
29
|
+
models = query.order_by(SessionModel.updated_at.desc()).all()
|
|
30
|
+
return [self._model_to_entity(model) for model in models]
|
|
31
|
+
|
|
32
|
+
def find_user_session(
|
|
33
|
+
self, session_id: SessionId, user_id: UserId
|
|
34
|
+
) -> Session | None:
|
|
35
|
+
"""Find a specific session belonging to a user."""
|
|
36
|
+
model = (
|
|
37
|
+
self.db.query(SessionModel)
|
|
38
|
+
.filter(
|
|
39
|
+
SessionModel.id == session_id,
|
|
40
|
+
SessionModel.user_id == user_id,
|
|
41
|
+
)
|
|
42
|
+
.first()
|
|
43
|
+
)
|
|
44
|
+
return self._model_to_entity(model) if model else None
|
|
45
|
+
|
|
46
|
+
def save(self, session: Session) -> Session:
|
|
47
|
+
"""Save or update a session."""
|
|
48
|
+
model = self.db.query(SessionModel).filter(SessionModel.id == session.id).first()
|
|
49
|
+
|
|
50
|
+
if model:
|
|
51
|
+
# Update existing
|
|
52
|
+
model.name = session.name
|
|
53
|
+
model.agent_id = session.agent_id
|
|
54
|
+
model.updated_at = session.updated_at
|
|
55
|
+
else:
|
|
56
|
+
# Create new
|
|
57
|
+
model = SessionModel(
|
|
58
|
+
id=session.id,
|
|
59
|
+
name=session.name,
|
|
60
|
+
user_id=session.user_id,
|
|
61
|
+
agent_id=session.agent_id,
|
|
62
|
+
created_at=session.created_at,
|
|
63
|
+
updated_at=session.updated_at,
|
|
64
|
+
)
|
|
65
|
+
self.db.add(model)
|
|
66
|
+
|
|
67
|
+
self.db.commit()
|
|
68
|
+
self.db.refresh(model)
|
|
69
|
+
return self._model_to_entity(model)
|
|
70
|
+
|
|
71
|
+
def delete(self, session_id: SessionId, user_id: UserId) -> bool:
|
|
72
|
+
"""Delete a session belonging to a user."""
|
|
73
|
+
result = (
|
|
74
|
+
self.db.query(SessionModel)
|
|
75
|
+
.filter(
|
|
76
|
+
SessionModel.id == session_id,
|
|
77
|
+
SessionModel.user_id == user_id,
|
|
78
|
+
)
|
|
79
|
+
.delete()
|
|
80
|
+
)
|
|
81
|
+
self.db.commit()
|
|
82
|
+
return result > 0
|
|
83
|
+
|
|
84
|
+
def find_user_session_with_messages(
|
|
85
|
+
self, session_id: SessionId, user_id: UserId, pagination: PaginationInfo | None = None
|
|
86
|
+
) -> tuple[Session, list[Message]] | None:
|
|
87
|
+
"""Find a session with its messages."""
|
|
88
|
+
session_model = (
|
|
89
|
+
self.db.query(SessionModel)
|
|
90
|
+
.filter(
|
|
91
|
+
SessionModel.id == session_id,
|
|
92
|
+
SessionModel.user_id == user_id,
|
|
93
|
+
)
|
|
94
|
+
.first()
|
|
95
|
+
)
|
|
96
|
+
|
|
97
|
+
if not session_model:
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
message_query = self.db.query(MessageModel).filter(
|
|
101
|
+
MessageModel.session_id == session_id
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
if pagination:
|
|
105
|
+
offset = (pagination.page - 1) * pagination.page_size
|
|
106
|
+
message_query = message_query.offset(offset).limit(pagination.page_size)
|
|
107
|
+
|
|
108
|
+
message_models = message_query.order_by(MessageModel.created_at.asc()).all()
|
|
109
|
+
|
|
110
|
+
session = self._model_to_entity(session_model)
|
|
111
|
+
messages = [self._message_model_to_entity(model) for model in message_models]
|
|
112
|
+
|
|
113
|
+
return session, messages
|
|
114
|
+
|
|
115
|
+
def _model_to_entity(self, model: SessionModel) -> Session:
|
|
116
|
+
"""Convert SQLAlchemy model to domain entity."""
|
|
117
|
+
return Session(
|
|
118
|
+
id=model.id,
|
|
119
|
+
user_id=model.user_id,
|
|
120
|
+
name=model.name,
|
|
121
|
+
agent_id=model.agent_id,
|
|
122
|
+
created_at=model.created_at,
|
|
123
|
+
updated_at=model.updated_at,
|
|
124
|
+
last_activity=model.updated_at,
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
def _message_model_to_entity(self, model: MessageModel) -> Message:
|
|
128
|
+
"""Convert SQLAlchemy message model to domain entity."""
|
|
129
|
+
from ..shared.enums import MessageType, SenderType
|
|
130
|
+
|
|
131
|
+
return Message(
|
|
132
|
+
id=model.id,
|
|
133
|
+
session_id=model.session_id,
|
|
134
|
+
message=model.message,
|
|
135
|
+
sender_type=SenderType(model.sender_type),
|
|
136
|
+
sender_name=model.sender_name,
|
|
137
|
+
message_type=MessageType.TEXT, # Default for now
|
|
138
|
+
created_at=model.created_at,
|
|
139
|
+
)
|
|
@@ -43,6 +43,7 @@ async def get_app_config(
|
|
|
43
43
|
"frontend_collect_feedback", False
|
|
44
44
|
),
|
|
45
45
|
"frontend_bot_name": component.get_config("frontend_bot_name", "A2A Agent"),
|
|
46
|
+
"frontend_feature_enablement": component.get_config("frontend_feature_enablement", {}),
|
|
46
47
|
"persistence_enabled": api_config.get("persistence_enabled", False),
|
|
47
48
|
}
|
|
48
49
|
log.info("%sReturning frontend configuration.", log_prefix)
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Request DTOs for API endpoints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .session_requests import (
|
|
6
|
+
GetSessionsRequest,
|
|
7
|
+
GetSessionRequest,
|
|
8
|
+
GetSessionHistoryRequest,
|
|
9
|
+
UpdateSessionRequest,
|
|
10
|
+
DeleteSessionRequest,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
# Session requests
|
|
15
|
+
"GetSessionsRequest",
|
|
16
|
+
"GetSessionRequest",
|
|
17
|
+
"GetSessionHistoryRequest",
|
|
18
|
+
"UpdateSessionRequest",
|
|
19
|
+
"DeleteSessionRequest",
|
|
20
|
+
]
|
|
@@ -39,11 +39,4 @@ class UpdateSessionRequest(BaseModel):
|
|
|
39
39
|
class DeleteSessionRequest(BaseModel):
|
|
40
40
|
"""Request DTO for deleting a session."""
|
|
41
41
|
session_id: SessionId
|
|
42
|
-
user_id: UserId
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class CreateSessionRequest(BaseModel):
|
|
46
|
-
"""Request DTO for creating a new session."""
|
|
47
|
-
user_id: UserId
|
|
48
|
-
name: Optional[str] = Field(None, max_length=255, description="Session name")
|
|
49
|
-
agent_id: Optional[str] = Field(None, description="Associated agent ID")
|
|
42
|
+
user_id: UserId
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Response DTOs for API endpoints.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from .session_responses import (
|
|
6
|
+
MessageResponse,
|
|
7
|
+
SessionResponse,
|
|
8
|
+
SessionListResponse,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
__all__ = [
|
|
12
|
+
# Session responses
|
|
13
|
+
"MessageResponse",
|
|
14
|
+
"SessionResponse",
|
|
15
|
+
"SessionListResponse",
|
|
16
|
+
]
|
|
@@ -4,10 +4,10 @@ Session-related response DTOs.
|
|
|
4
4
|
|
|
5
5
|
from typing import List, Optional
|
|
6
6
|
from datetime import datetime
|
|
7
|
-
from pydantic import BaseModel
|
|
7
|
+
from pydantic import BaseModel
|
|
8
8
|
|
|
9
|
-
from ....shared.types import SessionId, UserId, MessageId, PaginationInfo
|
|
10
|
-
from ....shared.enums import
|
|
9
|
+
from ....shared.types import SessionId, UserId, MessageId, PaginationInfo
|
|
10
|
+
from ....shared.enums import SenderType, MessageType
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
class MessageResponse(BaseModel):
|
|
@@ -29,7 +29,6 @@ class SessionResponse(BaseModel):
|
|
|
29
29
|
user_id: UserId
|
|
30
30
|
name: Optional[str] = None
|
|
31
31
|
agent_id: Optional[str] = None
|
|
32
|
-
status: SessionStatus = SessionStatus.ACTIVE
|
|
33
32
|
created_at: datetime
|
|
34
33
|
updated_at: Optional[datetime] = None
|
|
35
34
|
last_activity: Optional[datetime] = None
|
|
@@ -40,29 +39,3 @@ class SessionListResponse(BaseModel):
|
|
|
40
39
|
sessions: List[SessionResponse]
|
|
41
40
|
pagination: Optional[PaginationInfo] = None
|
|
42
41
|
total_count: int
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
class SessionHistoryResponse(BaseModel):
|
|
46
|
-
"""Response DTO for session message history."""
|
|
47
|
-
session_id: SessionId
|
|
48
|
-
messages: List[MessageResponse]
|
|
49
|
-
pagination: Optional[PaginationInfo] = None
|
|
50
|
-
total_count: int
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class SessionCreatedResponse(BaseModel):
|
|
54
|
-
"""Response DTO for session creation."""
|
|
55
|
-
session: SessionResponse
|
|
56
|
-
message: str = "Session created successfully"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class SessionUpdatedResponse(BaseModel):
|
|
60
|
-
"""Response DTO for session update."""
|
|
61
|
-
session: SessionResponse
|
|
62
|
-
message: str = "Session updated successfully"
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
class SessionDeletedResponse(BaseModel):
|
|
66
|
-
"""Response DTO for session deletion."""
|
|
67
|
-
session_id: SessionId
|
|
68
|
-
message: str = "Session deleted successfully"
|
solace_agent_mesh/gateway/http_sse/{api/controllers/session_controller.py → routers/sessions.py}
RENAMED
|
@@ -1,22 +1,19 @@
|
|
|
1
|
-
from fastapi import APIRouter, Body, Depends, HTTPException, status
|
|
1
|
+
from fastapi import APIRouter, Body, Depends, HTTPException, status, BackgroundTasks
|
|
2
2
|
from solace_ai_connector.common.log import log
|
|
3
3
|
|
|
4
|
-
from
|
|
5
|
-
from
|
|
6
|
-
|
|
7
|
-
get_namespace,
|
|
8
|
-
get_publish_a2a_func,
|
|
9
|
-
get_session_service,
|
|
4
|
+
from ..services.session_service import SessionService
|
|
5
|
+
from ..dependencies import (
|
|
6
|
+
get_session_business_service,
|
|
10
7
|
)
|
|
11
|
-
from
|
|
12
|
-
from
|
|
8
|
+
from ..shared.auth_utils import get_current_user
|
|
9
|
+
from .dto.requests.session_requests import (
|
|
13
10
|
DeleteSessionRequest,
|
|
14
11
|
GetSessionHistoryRequest,
|
|
15
12
|
GetSessionRequest,
|
|
16
13
|
GetSessionsRequest,
|
|
17
14
|
UpdateSessionRequest,
|
|
18
15
|
)
|
|
19
|
-
from
|
|
16
|
+
from .dto.responses.session_responses import (
|
|
20
17
|
MessageResponse,
|
|
21
18
|
SessionListResponse,
|
|
22
19
|
SessionResponse,
|
|
@@ -28,7 +25,7 @@ router = APIRouter()
|
|
|
28
25
|
@router.get("/sessions", response_model=SessionListResponse)
|
|
29
26
|
async def get_all_sessions(
|
|
30
27
|
user: dict = Depends(get_current_user),
|
|
31
|
-
session_service: SessionService = Depends(
|
|
28
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
32
29
|
):
|
|
33
30
|
user_id = user.get("id")
|
|
34
31
|
log.info("Fetching sessions for user_id: %s", user_id)
|
|
@@ -47,7 +44,6 @@ async def get_all_sessions(
|
|
|
47
44
|
user_id=domain.user_id,
|
|
48
45
|
name=domain.name,
|
|
49
46
|
agent_id=domain.agent_id,
|
|
50
|
-
status=domain.status,
|
|
51
47
|
created_at=domain.created_at,
|
|
52
48
|
updated_at=domain.updated_at,
|
|
53
49
|
last_activity=domain.last_activity,
|
|
@@ -72,7 +68,7 @@ async def get_all_sessions(
|
|
|
72
68
|
async def get_session(
|
|
73
69
|
session_id: str,
|
|
74
70
|
user: dict = Depends(get_current_user),
|
|
75
|
-
session_service: SessionService = Depends(
|
|
71
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
76
72
|
):
|
|
77
73
|
user_id = user.get("id")
|
|
78
74
|
log.info("User %s attempting to fetch session_id: %s", user_id, session_id)
|
|
@@ -89,7 +85,7 @@ async def get_session(
|
|
|
89
85
|
|
|
90
86
|
request_dto = GetSessionRequest(session_id=session_id, user_id=user_id)
|
|
91
87
|
|
|
92
|
-
session_domain = session_service.
|
|
88
|
+
session_domain = session_service.get_session_details(
|
|
93
89
|
session_id=request_dto.session_id, user_id=request_dto.user_id
|
|
94
90
|
)
|
|
95
91
|
|
|
@@ -105,7 +101,6 @@ async def get_session(
|
|
|
105
101
|
user_id=session_domain.user_id,
|
|
106
102
|
name=session_domain.name,
|
|
107
103
|
agent_id=session_domain.agent_id,
|
|
108
|
-
status=session_domain.status,
|
|
109
104
|
created_at=session_domain.created_at,
|
|
110
105
|
updated_at=session_domain.updated_at,
|
|
111
106
|
last_activity=session_domain.last_activity,
|
|
@@ -130,7 +125,7 @@ async def get_session(
|
|
|
130
125
|
async def get_session_history(
|
|
131
126
|
session_id: str,
|
|
132
127
|
user: dict = Depends(get_current_user),
|
|
133
|
-
session_service: SessionService = Depends(
|
|
128
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
134
129
|
):
|
|
135
130
|
user_id = user.get("id")
|
|
136
131
|
log.info(
|
|
@@ -202,7 +197,7 @@ async def update_session_name(
|
|
|
202
197
|
session_id: str,
|
|
203
198
|
name: str = Body(..., embed=True),
|
|
204
199
|
user: dict = Depends(get_current_user),
|
|
205
|
-
session_service: SessionService = Depends(
|
|
200
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
206
201
|
):
|
|
207
202
|
user_id = user.get("id")
|
|
208
203
|
log.info("User %s attempting to update session %s", user_id, session_id)
|
|
@@ -239,7 +234,6 @@ async def update_session_name(
|
|
|
239
234
|
user_id=updated_domain.user_id,
|
|
240
235
|
name=updated_domain.name,
|
|
241
236
|
agent_id=updated_domain.agent_id,
|
|
242
|
-
status=updated_domain.status,
|
|
243
237
|
created_at=updated_domain.created_at,
|
|
244
238
|
updated_at=updated_domain.updated_at,
|
|
245
239
|
last_activity=updated_domain.last_activity,
|
|
@@ -269,36 +263,14 @@ async def update_session_name(
|
|
|
269
263
|
async def delete_session(
|
|
270
264
|
session_id: str,
|
|
271
265
|
user: dict = Depends(get_current_user),
|
|
272
|
-
session_service: SessionService = Depends(
|
|
273
|
-
publish_func: PublishFunc = Depends(get_publish_a2a_func),
|
|
274
|
-
namespace: str = Depends(get_namespace),
|
|
266
|
+
session_service: SessionService = Depends(get_session_business_service),
|
|
275
267
|
):
|
|
276
268
|
user_id = user.get("id")
|
|
277
269
|
log.info("User %s attempting to delete session %s", user_id, session_id)
|
|
278
270
|
|
|
279
271
|
try:
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
or session_id.strip() == ""
|
|
283
|
-
or session_id in ["null", "undefined"]
|
|
284
|
-
):
|
|
285
|
-
raise HTTPException(
|
|
286
|
-
status_code=status.HTTP_404_NOT_FOUND, detail="Session not found."
|
|
287
|
-
)
|
|
288
|
-
|
|
289
|
-
request_dto = DeleteSessionRequest(session_id=session_id, user_id=user_id)
|
|
290
|
-
|
|
291
|
-
# Get session details before deletion to find the agent_id
|
|
292
|
-
session = session_service.get_session(session_id=session_id, user_id=user_id)
|
|
293
|
-
if not session:
|
|
294
|
-
raise HTTPException(
|
|
295
|
-
status_code=status.HTTP_404_NOT_FOUND, detail="Session not found."
|
|
296
|
-
)
|
|
297
|
-
|
|
298
|
-
agent_id = session.agent_id
|
|
299
|
-
|
|
300
|
-
deleted = session_service.delete_session(
|
|
301
|
-
session_id=request_dto.session_id, user_id=request_dto.user_id
|
|
272
|
+
deleted = session_service.delete_session_with_notifications(
|
|
273
|
+
session_id=session_id, user_id=user_id
|
|
302
274
|
)
|
|
303
275
|
|
|
304
276
|
if not deleted:
|
|
@@ -308,40 +280,11 @@ async def delete_session(
|
|
|
308
280
|
|
|
309
281
|
log.info("Session %s deleted successfully", session_id)
|
|
310
282
|
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
control_message = {
|
|
318
|
-
"control": {
|
|
319
|
-
"action": "delete_session",
|
|
320
|
-
"session_id": session_id,
|
|
321
|
-
"user_id": user_id,
|
|
322
|
-
}
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
target_topic = get_agent_request_topic(namespace, agent_id)
|
|
326
|
-
|
|
327
|
-
log.info(
|
|
328
|
-
"Sending session deletion notification to agent %s for session %s",
|
|
329
|
-
agent_id,
|
|
330
|
-
session_id,
|
|
331
|
-
)
|
|
332
|
-
|
|
333
|
-
publish_func(target_topic, control_message, None)
|
|
334
|
-
|
|
335
|
-
except Exception as e:
|
|
336
|
-
log.warning(
|
|
337
|
-
"Failed to notify agent %s about session %s deletion: %s",
|
|
338
|
-
agent_id,
|
|
339
|
-
session_id,
|
|
340
|
-
e,
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
except HTTPException:
|
|
344
|
-
raise
|
|
283
|
+
except ValueError as e:
|
|
284
|
+
log.warning("Validation error deleting session %s: %s", session_id, e)
|
|
285
|
+
raise HTTPException(
|
|
286
|
+
status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)
|
|
287
|
+
)
|
|
345
288
|
except Exception as e:
|
|
346
289
|
log.error(
|
|
347
290
|
"Error deleting session %s for user %s: %s",
|
|
@@ -105,60 +105,53 @@ async def _submit_task(
|
|
|
105
105
|
|
|
106
106
|
# Store message in persistence layer if available
|
|
107
107
|
user_id = user_identity.get("id")
|
|
108
|
-
|
|
108
|
+
from ....gateway.http_sse.dependencies import SessionLocal
|
|
109
|
+
if is_streaming and SessionLocal is not None:
|
|
109
110
|
try:
|
|
110
|
-
from ....gateway.http_sse.dependencies import
|
|
111
|
+
from ....gateway.http_sse.dependencies import create_session_service_with_transaction
|
|
111
112
|
from ....gateway.http_sse.shared.enums import SenderType
|
|
112
113
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
agent_id=agent_name,
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
if message_domain:
|
|
156
|
-
log.info("%sMessage stored in session %s", log_prefix, session_id)
|
|
157
|
-
else:
|
|
158
|
-
log.warning("%sFailed to store message in session %s", log_prefix, session_id)
|
|
114
|
+
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
|
+
message_text = ""
|
|
133
|
+
if payload.params and payload.params.message:
|
|
134
|
+
parts = a2a.get_parts_from_message(payload.params.message)
|
|
135
|
+
for part in parts:
|
|
136
|
+
if hasattr(part, 'text'):
|
|
137
|
+
message_text = part.text
|
|
138
|
+
break
|
|
139
|
+
|
|
140
|
+
message_domain = session_service.add_message_to_session(
|
|
141
|
+
session_id=session_id,
|
|
142
|
+
user_id=user_id,
|
|
143
|
+
message=message_text or "Task submitted",
|
|
144
|
+
sender_type=SenderType.USER,
|
|
145
|
+
sender_name=user_id or "user",
|
|
146
|
+
agent_id=agent_name,
|
|
147
|
+
)
|
|
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)
|
|
159
153
|
except Exception as e:
|
|
160
154
|
log.error("%sFailed to store message in session service: %s", log_prefix, e)
|
|
161
|
-
# Don't fail the request, just log the error
|
|
162
155
|
else:
|
|
163
156
|
log.debug("%sNo persistence available or non-streaming - skipping message storage", log_prefix)
|
|
164
157
|
|