solace-agent-mesh 1.1.0__py3-none-any.whl → 1.3.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/runner.py +18 -12
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/protocol/event_handlers.py +27 -21
- solace_agent_mesh/agent/sac/app.py +1 -1
- solace_agent_mesh/agent/sac/component.py +0 -1
- solace_agent_mesh/assets/docs/404.html +2 -2
- solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js → main.08d30374.js} +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +2 -2
- solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
- solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
- solace_agent_mesh/cli/commands/run_cmd.py +5 -3
- solace_agent_mesh/cli/utils.py +68 -12
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
- solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
- solace_agent_mesh/config_portal/backend/common.py +2 -2
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/evaluation/message_organizer.py +35 -56
- solace_agent_mesh/evaluation/run.py +26 -5
- solace_agent_mesh/evaluation/subscriber.py +35 -10
- solace_agent_mesh/evaluation/summary_builder.py +27 -34
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
- solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
- solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
- solace_agent_mesh/gateway/http_sse/app.py +31 -1
- solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
- solace_agent_mesh/gateway/http_sse/component.py +224 -62
- solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
- solace_agent_mesh/gateway/http_sse/main.py +289 -85
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +121 -54
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +83 -2
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
- solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
- solace_agent_mesh/templates/shared_config.yaml +4 -5
- solace_agent_mesh/templates/webui.yaml +8 -10
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +5 -3
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +130 -91
- solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1756992446316.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
- solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +0 -699
- solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -85
- solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
- /solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.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,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
|
+
)
|