solace-agent-mesh 1.1.0__py3-none-any.whl → 1.3.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of solace-agent-mesh might be problematic. Click here for more details.

Files changed (168) hide show
  1. solace_agent_mesh/agent/adk/runner.py +18 -12
  2. solace_agent_mesh/agent/adk/services.py +3 -3
  3. solace_agent_mesh/agent/adk/setup.py +141 -34
  4. solace_agent_mesh/agent/protocol/event_handlers.py +27 -21
  5. solace_agent_mesh/agent/sac/app.py +0 -1
  6. solace_agent_mesh/agent/sac/component.py +0 -1
  7. solace_agent_mesh/agent/tools/__init__.py +1 -0
  8. solace_agent_mesh/agent/tools/dynamic_tool.py +362 -0
  9. solace_agent_mesh/assets/docs/404.html +3 -3
  10. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.d97b8e94.js +1 -0
  11. solace_agent_mesh/assets/docs/assets/js/483cef9a.4e972867.js +1 -0
  12. solace_agent_mesh/assets/docs/assets/js/55f47984.cf3781c4.js +1 -0
  13. solace_agent_mesh/assets/docs/assets/js/664b740a.1b744a32.js +1 -0
  14. solace_agent_mesh/assets/docs/assets/js/75384d09.c193a8f0.js +1 -0
  15. solace_agent_mesh/assets/docs/assets/js/9a09e75d.d6607c56.js +1 -0
  16. solace_agent_mesh/assets/docs/assets/js/aba87c2f.071e2d94.js +1 -0
  17. solace_agent_mesh/assets/docs/assets/js/ae0e903d.4d8dda10.js +1 -0
  18. solace_agent_mesh/assets/docs/assets/js/c835a94d.146e3186.js +1 -0
  19. solace_agent_mesh/assets/docs/assets/js/f284c35a.7334119c.js +1 -0
  20. solace_agent_mesh/assets/docs/assets/js/main.1c79039d.js +2 -0
  21. solace_agent_mesh/assets/docs/assets/js/runtime~main.858117b7.js +1 -0
  22. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/installation/index.html +29 -0
  23. solace_agent_mesh/assets/docs/docs/documentation/Enterprise/single-sign-on/index.html +25 -0
  24. solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html } +6 -6
  25. solace_agent_mesh/assets/docs/docs/documentation/{migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html → Migrations/A2A Upgrade To 0.3.0/a2a-technical-migration-map/index.html } +6 -6
  26. solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +19 -27
  27. solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +4 -4
  28. solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +4 -4
  29. solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +4 -4
  30. solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +4 -4
  31. solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +4 -4
  32. solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +4 -4
  33. solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +4 -4
  34. solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +4 -4
  35. solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +4 -4
  36. solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +4 -4
  37. solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +4 -4
  38. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  39. solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +4 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +4 -4
  44. solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +4 -4
  45. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +4 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +4 -4
  53. solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +5 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +4 -4
  56. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-python-tools/index.html +63 -0
  57. solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +4 -4
  60. solace_agent_mesh/assets/docs/lunr-index-1757531604543.json +1 -0
  61. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  62. solace_agent_mesh/assets/docs/search-doc-1757531604543.json +1 -0
  63. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  64. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  65. solace_agent_mesh/cli/__init__.py +1 -1
  66. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
  67. solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
  68. solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
  69. solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
  70. solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
  71. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
  72. solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
  73. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
  74. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
  75. solace_agent_mesh/cli/commands/run_cmd.py +5 -3
  76. solace_agent_mesh/cli/utils.py +68 -12
  77. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-CAX9u8a7.js +1 -0
  78. solace_agent_mesh/client/webui/frontend/static/assets/client-DXU9SPI5.js +25 -0
  79. solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
  80. solace_agent_mesh/client/webui/frontend/static/assets/main-C1k9E0aC.js +339 -0
  81. solace_agent_mesh/client/webui/frontend/static/assets/vendor-B0BEKoAR.js +390 -0
  82. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
  83. solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
  84. solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
  85. solace_agent_mesh/config_portal/backend/common.py +2 -2
  86. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
  87. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
  88. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  89. solace_agent_mesh/evaluation/message_organizer.py +35 -56
  90. solace_agent_mesh/evaluation/run.py +26 -5
  91. solace_agent_mesh/evaluation/subscriber.py +35 -10
  92. solace_agent_mesh/evaluation/summary_builder.py +27 -34
  93. solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
  94. solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
  95. solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
  96. solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
  97. solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
  98. solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
  99. solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
  100. solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
  101. solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
  102. solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
  103. solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
  104. solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
  105. solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
  106. solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
  107. solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
  108. solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
  109. solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
  110. solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
  111. solace_agent_mesh/gateway/http_sse/app.py +31 -1
  112. solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
  113. solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
  114. solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
  115. solace_agent_mesh/gateway/http_sse/component.py +224 -62
  116. solace_agent_mesh/gateway/http_sse/dependencies.py +148 -45
  117. solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
  118. solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
  119. solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
  120. solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
  121. solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
  122. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
  123. solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
  124. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
  125. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
  126. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
  127. solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
  128. solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
  129. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
  130. solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
  131. solace_agent_mesh/gateway/http_sse/main.py +291 -87
  132. solace_agent_mesh/gateway/http_sse/routers/{agents.py → agent_cards.py} +7 -7
  133. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +121 -54
  134. solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
  135. solace_agent_mesh/gateway/http_sse/routers/tasks.py +83 -2
  136. solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
  137. solace_agent_mesh/gateway/http_sse/services/{agent_service.py → agent_card_service.py} +19 -19
  138. solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
  139. solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
  140. solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
  141. solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
  142. solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
  143. solace_agent_mesh/templates/shared_config.yaml +4 -5
  144. solace_agent_mesh/templates/webui.yaml +8 -10
  145. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/METADATA +5 -3
  146. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/RECORD +150 -104
  147. solace_agent_mesh/assets/docs/assets/js/42b3f8d8.8ccb9901.js +0 -1
  148. solace_agent_mesh/assets/docs/assets/js/55f47984.c484bf96.js +0 -1
  149. solace_agent_mesh/assets/docs/assets/js/6e0db977.39a79ca9.js +0 -1
  150. solace_agent_mesh/assets/docs/assets/js/75384d09.bf78fbdb.js +0 -1
  151. solace_agent_mesh/assets/docs/assets/js/90dd9cf6.88f385ea.js +0 -1
  152. solace_agent_mesh/assets/docs/assets/js/aba87c2f.76376d7c.js +0 -1
  153. solace_agent_mesh/assets/docs/assets/js/f284c35a.fb68323a.js +0 -1
  154. solace_agent_mesh/assets/docs/assets/js/main.a75ecc0d.js +0 -2
  155. solace_agent_mesh/assets/docs/assets/js/runtime~main.458efb1d.js +0 -1
  156. solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +0 -1
  157. solace_agent_mesh/assets/docs/search-doc-1756992446316.json +0 -1
  158. solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
  159. solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
  160. solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +0 -699
  161. solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +0 -1
  162. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
  163. solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -85
  164. solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
  165. /solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js.LICENSE.txt → main.1c79039d.js.LICENSE.txt} +0 -0
  166. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/WHEEL +0 -0
  167. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/entry_points.txt +0 -0
  168. {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,119 @@
1
+ import logging
2
+ from collections.abc import Generator
3
+ from contextlib import contextmanager
4
+
5
+ from sqlalchemy import create_engine, event
6
+ from sqlalchemy.orm import Session, sessionmaker
7
+
8
+ from .models import Base
9
+
10
+
11
+ def get_database_type(database_url: str) -> str:
12
+ """Get the database type from a database URL."""
13
+ if database_url.startswith("sqlite"):
14
+ return "sqlite"
15
+ elif database_url.startswith("postgresql"):
16
+ return "postgresql"
17
+ else:
18
+ return "unknown"
19
+
20
+
21
+ class DatabaseService:
22
+ def __init__(self, database_url: str):
23
+ self.database_url = database_url
24
+ self.logger = logging.getLogger(__name__)
25
+
26
+ if database_url.startswith("sqlite"):
27
+ self._setup_sqlite_engine(database_url)
28
+ elif database_url.startswith("postgresql"):
29
+ self._setup_postgresql_engine(database_url)
30
+ else:
31
+ # Fallback for other databases
32
+ self._setup_generic_engine(database_url)
33
+
34
+ self.SessionLocal = sessionmaker(
35
+ autocommit=False, autoflush=False, bind=self.engine
36
+ )
37
+
38
+ def _setup_sqlite_engine(self, database_url: str):
39
+ """Configure SQLite-specific engine settings."""
40
+ self.engine = create_engine(
41
+ database_url,
42
+ echo=False,
43
+ connect_args={
44
+ "check_same_thread": False,
45
+ },
46
+ )
47
+
48
+ @event.listens_for(self.engine, "connect")
49
+ def set_sqlite_pragma(dbapi_connection, connection_record):
50
+ cursor = dbapi_connection.cursor()
51
+ cursor.execute("PRAGMA foreign_keys=ON")
52
+ cursor.close()
53
+
54
+ def _setup_postgresql_engine(self, database_url: str):
55
+ """Configure PostgreSQL-specific engine settings."""
56
+ try:
57
+ import psycopg2
58
+ except ImportError:
59
+ raise ImportError(
60
+ "PostgreSQL support requires psycopg2. Install with: "
61
+ "pip install 'solace-agent-mesh[postgresql]'"
62
+ )
63
+
64
+ self.engine = create_engine(
65
+ database_url,
66
+ pool_size=10,
67
+ max_overflow=20,
68
+ pool_timeout=30,
69
+ pool_recycle=3600,
70
+ pool_pre_ping=True,
71
+ echo=False,
72
+ )
73
+
74
+ def _setup_generic_engine(self, database_url: str):
75
+ """Configure generic database engine settings."""
76
+ self.engine = create_engine(
77
+ database_url,
78
+ pool_size=10,
79
+ max_overflow=20,
80
+ pool_timeout=30,
81
+ pool_recycle=3600,
82
+ pool_pre_ping=True,
83
+ echo=False,
84
+ )
85
+
86
+ def create_tables(self):
87
+ Base.metadata.create_all(bind=self.engine)
88
+
89
+ @contextmanager
90
+ def session_scope(self) -> Generator[Session, None, None]:
91
+ session = self.SessionLocal()
92
+ try:
93
+ yield session
94
+ session.commit()
95
+ except Exception as e:
96
+ session.rollback()
97
+ self.logger.error(f"Database transaction failed: {e}")
98
+ raise
99
+ finally:
100
+ session.close()
101
+
102
+ @contextmanager
103
+ def read_only_session(self) -> Generator[Session, None, None]:
104
+ session = self.SessionLocal()
105
+ try:
106
+ yield session
107
+ except Exception as e:
108
+ session.rollback()
109
+ self.logger.error(f"Database read operation failed: {e}")
110
+ raise
111
+ finally:
112
+ session.close()
113
+
114
+
115
+ database_service: DatabaseService = None
116
+
117
+
118
+ def get_database_service() -> DatabaseService:
119
+ return database_service
@@ -0,0 +1,31 @@
1
+ from sqlalchemy import Column, DateTime, ForeignKey, String, Text
2
+ from sqlalchemy.orm import declarative_base, relationship
3
+ from sqlalchemy.sql import func
4
+
5
+ Base = declarative_base()
6
+
7
+
8
+ class SessionModel(Base):
9
+ __tablename__ = "sessions"
10
+ id = Column(String, primary_key=True)
11
+ name = Column(String, nullable=True)
12
+ user_id = Column(String, nullable=False)
13
+ agent_id = Column(String, nullable=True)
14
+ created_at = Column(DateTime, default=func.now())
15
+ updated_at = Column(DateTime, default=func.now(), onupdate=func.now())
16
+ messages = relationship(
17
+ "MessageModel", back_populates="session", cascade="all, delete-orphan"
18
+ )
19
+
20
+
21
+ class MessageModel(Base):
22
+ __tablename__ = "chat_messages"
23
+ id = Column(String, primary_key=True)
24
+ session_id = Column(
25
+ String, ForeignKey("sessions.id", ondelete="CASCADE"), nullable=False
26
+ )
27
+ message = Column(Text, nullable=False)
28
+ created_at = Column(DateTime, default=func.now())
29
+ sender_type = Column(String(50))
30
+ sender_name = Column(String(255))
31
+ session = relationship("SessionModel", back_populates="messages")
@@ -0,0 +1,12 @@
1
+ from .dependency_injection.container import ApplicationContainer
2
+ from .persistence.database_service import DatabaseService
3
+
4
+
5
+ class PersistenceService:
6
+ def __init__(self, database_url: str):
7
+ self.db_service = DatabaseService(database_url)
8
+ self.container = ApplicationContainer(database_url)
9
+
10
+ @property
11
+ def engine(self):
12
+ return self.db_service.engine
@@ -0,0 +1,3 @@
1
+ from .session_repository import SessionRepository, MessageRepository
2
+
3
+ __all__ = ["SessionRepository", "MessageRepository"]
@@ -0,0 +1,174 @@
1
+ from ...domain.entities.session import Message, Session
2
+ from ...domain.repositories.session_repository import (
3
+ IMessageRepository,
4
+ ISessionRepository,
5
+ )
6
+ from ...shared.enums import SenderType, SessionStatus
7
+ from ...shared.types import PaginationInfo, SessionId, UserId
8
+ from ..persistence.database_service import DatabaseService
9
+ from ..persistence.models import MessageModel, SessionModel
10
+
11
+
12
+ class SessionRepository(ISessionRepository):
13
+ def __init__(self, db_service: DatabaseService):
14
+ self.db_service = db_service
15
+
16
+ def get_by_id(self, session_id: SessionId) -> Session | None:
17
+ with self.db_service.read_only_session() as session:
18
+ model = (
19
+ session.query(SessionModel)
20
+ .filter(SessionModel.id == session_id)
21
+ .first()
22
+ )
23
+ return self._model_to_entity(model) if model else None
24
+
25
+ def get_by_user_id(
26
+ self, user_id: UserId, pagination: PaginationInfo | None = None
27
+ ) -> list[Session]:
28
+ with self.db_service.read_only_session() as session:
29
+ query = session.query(SessionModel).filter(SessionModel.user_id == user_id)
30
+
31
+ if pagination:
32
+ offset = (pagination.page - 1) * pagination.page_size
33
+ query = query.offset(offset).limit(pagination.page_size)
34
+
35
+ models = query.order_by(SessionModel.updated_at.desc()).all()
36
+ return [self._model_to_entity(model) for model in models]
37
+
38
+ def get_user_session(
39
+ self, session_id: SessionId, user_id: UserId
40
+ ) -> Session | None:
41
+ with self.db_service.read_only_session() as session:
42
+ model = (
43
+ session.query(SessionModel)
44
+ .filter(SessionModel.id == session_id, SessionModel.user_id == user_id)
45
+ .first()
46
+ )
47
+ return self._model_to_entity(model) if model else None
48
+
49
+ def create(self, session_entity: Session) -> Session:
50
+ with self.db_service.session_scope() as session:
51
+ model = SessionModel(
52
+ id=session_entity.id,
53
+ user_id=session_entity.user_id,
54
+ name=session_entity.name,
55
+ agent_id=session_entity.agent_id,
56
+ created_at=session_entity.created_at,
57
+ updated_at=session_entity.updated_at,
58
+ )
59
+ session.add(model)
60
+ session.flush()
61
+ session.refresh(model)
62
+ return self._model_to_entity(model)
63
+
64
+ def update(self, session_entity: Session) -> Session | None:
65
+ with self.db_service.session_scope() as session:
66
+ model = (
67
+ session.query(SessionModel)
68
+ .filter(
69
+ SessionModel.id == session_entity.id,
70
+ SessionModel.user_id == session_entity.user_id,
71
+ )
72
+ .first()
73
+ )
74
+
75
+ if not model:
76
+ return None
77
+
78
+ model.name = session_entity.name
79
+ model.agent_id = session_entity.agent_id
80
+ model.updated_at = session_entity.updated_at
81
+
82
+ session.flush()
83
+ session.refresh(model)
84
+ return self._model_to_entity(model)
85
+
86
+ def delete(self, session_id: SessionId, user_id: UserId) -> bool:
87
+ with self.db_service.session_scope() as session:
88
+ model = (
89
+ session.query(SessionModel)
90
+ .filter(SessionModel.id == session_id, SessionModel.user_id == user_id)
91
+ .first()
92
+ )
93
+
94
+ if not model:
95
+ return False
96
+
97
+ session.delete(model)
98
+ return True
99
+
100
+ def exists(self, session_id: SessionId) -> bool:
101
+ with self.db_service.read_only_session() as session:
102
+ return (
103
+ session.query(SessionModel)
104
+ .filter(SessionModel.id == session_id)
105
+ .first()
106
+ is not None
107
+ )
108
+
109
+ def _model_to_entity(self, model: SessionModel) -> Session:
110
+ return Session(
111
+ id=model.id,
112
+ user_id=model.user_id,
113
+ name=model.name,
114
+ agent_id=model.agent_id,
115
+ status=SessionStatus.ACTIVE,
116
+ created_at=model.created_at,
117
+ updated_at=model.updated_at,
118
+ last_activity=model.updated_at,
119
+ )
120
+
121
+
122
+ class MessageRepository(IMessageRepository):
123
+ def __init__(self, db_service: DatabaseService):
124
+ self.db_service = db_service
125
+
126
+ def get_by_session_id(
127
+ self, session_id: SessionId, pagination: PaginationInfo | None = None
128
+ ) -> list[Message]:
129
+ with self.db_service.read_only_session() as session:
130
+ query = session.query(MessageModel).filter(
131
+ MessageModel.session_id == session_id
132
+ )
133
+ query = query.order_by(MessageModel.created_at.asc())
134
+
135
+ if pagination:
136
+ offset = (pagination.page - 1) * pagination.page_size
137
+ query = query.offset(offset).limit(pagination.page_size)
138
+
139
+ models = query.all()
140
+ return [self._model_to_entity(model) for model in models]
141
+
142
+ def create(self, message_entity: Message) -> Message:
143
+ with self.db_service.session_scope() as session:
144
+ model = MessageModel(
145
+ id=message_entity.id,
146
+ session_id=message_entity.session_id,
147
+ message=message_entity.message,
148
+ sender_type=message_entity.sender_type.value,
149
+ sender_name=message_entity.sender_name,
150
+ created_at=message_entity.created_at,
151
+ )
152
+ session.add(model)
153
+ session.flush()
154
+ session.refresh(model)
155
+ return self._model_to_entity(model)
156
+
157
+ def delete_by_session_id(self, session_id: SessionId) -> bool:
158
+ with self.db_service.session_scope() as session:
159
+ deleted_count = (
160
+ session.query(MessageModel)
161
+ .filter(MessageModel.session_id == session_id)
162
+ .delete()
163
+ )
164
+ return deleted_count > 0
165
+
166
+ def _model_to_entity(self, model: MessageModel) -> Message:
167
+ return Message(
168
+ id=model.id,
169
+ session_id=model.session_id,
170
+ message=model.message,
171
+ sender_type=SenderType(model.sender_type),
172
+ sender_name=model.sender_name,
173
+ created_at=model.created_at,
174
+ )