solace-agent-mesh 1.5.1__py3-none-any.whl → 1.6.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.

Files changed (180) hide show
  1. solace_agent_mesh/agent/adk/callbacks.py +0 -5
  2. solace_agent_mesh/agent/adk/models/lite_llm.py +123 -8
  3. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +245 -0
  4. solace_agent_mesh/agent/protocol/event_handlers.py +40 -1
  5. solace_agent_mesh/agent/proxies/__init__.py +0 -0
  6. solace_agent_mesh/agent/proxies/a2a/__init__.py +3 -0
  7. solace_agent_mesh/agent/proxies/a2a/app.py +55 -0
  8. solace_agent_mesh/agent/proxies/a2a/component.py +1115 -0
  9. solace_agent_mesh/agent/proxies/a2a/config.py +140 -0
  10. solace_agent_mesh/agent/proxies/a2a/oauth_token_cache.py +104 -0
  11. solace_agent_mesh/agent/proxies/base/__init__.py +3 -0
  12. solace_agent_mesh/agent/proxies/base/app.py +99 -0
  13. solace_agent_mesh/agent/proxies/base/component.py +619 -0
  14. solace_agent_mesh/agent/proxies/base/config.py +85 -0
  15. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +17 -0
  16. solace_agent_mesh/agent/sac/app.py +9 -3
  17. solace_agent_mesh/agent/sac/component.py +160 -8
  18. solace_agent_mesh/agent/tools/audio_tools.py +125 -8
  19. solace_agent_mesh/agent/tools/web_tools.py +10 -5
  20. solace_agent_mesh/agent/utils/artifact_helpers.py +141 -3
  21. solace_agent_mesh/assets/docs/404.html +3 -3
  22. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +1 -0
  23. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +1 -0
  25. solace_agent_mesh/assets/docs/assets/js/77cf947d.48cb18a2.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.570c057b.js +1 -0
  28. solace_agent_mesh/assets/docs/assets/js/{ad71b5ed.60668e9e.js → ad71b5ed.af3ecfd1.js} +1 -1
  29. solace_agent_mesh/assets/docs/assets/js/ceb2a7a6.5d92d7d0.js +1 -0
  30. solace_agent_mesh/assets/docs/assets/js/{da0b5bad.9d369087.js → da0b5bad.d08a9466.js} +1 -1
  31. solace_agent_mesh/assets/docs/assets/js/db924877.e98d12a1.js +1 -0
  32. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +1 -0
  34. solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +1 -0
  35. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +1 -0
  36. solace_agent_mesh/assets/docs/assets/js/{main.bd3c34f3.js → main.20feee82.js} +2 -2
  37. solace_agent_mesh/assets/docs/assets/js/runtime~main.0d198646.js +1 -0
  38. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +15 -4
  39. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
  40. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
  41. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
  44. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
  45. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
  47. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
  48. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
  49. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +262 -0
  50. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +3 -3
  51. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +31 -3
  52. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +3 -3
  53. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +3 -3
  54. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +5 -5
  56. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +135 -0
  59. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +6 -4
  60. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +5 -5
  64. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
  65. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
  66. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
  67. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
  68. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
  69. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
  70. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +3 -3
  71. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +3 -3
  72. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +3 -3
  73. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +3 -3
  74. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +3 -3
  75. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +3 -3
  76. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  77. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
  78. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +6 -5
  79. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +3 -3
  80. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +3 -3
  81. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +100 -3
  82. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +3 -3
  83. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
  84. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
  85. solace_agent_mesh/assets/docs/lunr-index-1761165361160.json +1 -0
  86. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  87. solace_agent_mesh/assets/docs/search-doc-1761165361160.json +1 -0
  88. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  89. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  90. solace_agent_mesh/cli/__init__.py +1 -1
  91. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +2 -69
  92. solace_agent_mesh/cli/commands/eval_cmd.py +11 -49
  93. solace_agent_mesh/cli/commands/init_cmd/__init__.py +0 -5
  94. solace_agent_mesh/cli/commands/init_cmd/env_step.py +10 -12
  95. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +9 -61
  96. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +9 -49
  97. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +1 -2
  98. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-DwrxZE0E.js → authCallback-BTf6dqwp.js} +1 -1
  99. solace_agent_mesh/client/webui/frontend/static/assets/{client-DarGQzyw.js → client-CaY59VuC.js} +1 -1
  100. solace_agent_mesh/client/webui/frontend/static/assets/main-BGTaW0uv.js +342 -0
  101. solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +1 -0
  102. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BKIeiHj_.js → vendor-BEmvJSYz.js} +1 -1
  103. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  104. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  105. solace_agent_mesh/common/a2a/__init__.py +24 -0
  106. solace_agent_mesh/common/a2a/artifact.py +39 -0
  107. solace_agent_mesh/common/a2a/events.py +29 -0
  108. solace_agent_mesh/common/a2a/message.py +68 -0
  109. solace_agent_mesh/common/a2a/protocol.py +73 -1
  110. solace_agent_mesh/common/agent_registry.py +83 -3
  111. solace_agent_mesh/common/constants.py +3 -1
  112. solace_agent_mesh/common/utils/pydantic_utils.py +12 -0
  113. solace_agent_mesh/config_portal/backend/common.py +1 -1
  114. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +98 -0
  115. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-44d62be6.js → manifest-61038fc6.js} +1 -1
  116. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  117. solace_agent_mesh/evaluation/evaluator.py +128 -104
  118. solace_agent_mesh/evaluation/message_organizer.py +116 -110
  119. solace_agent_mesh/evaluation/report_data_processor.py +84 -86
  120. solace_agent_mesh/evaluation/report_generator.py +73 -79
  121. solace_agent_mesh/evaluation/run.py +421 -235
  122. solace_agent_mesh/evaluation/shared/__init__.py +92 -0
  123. solace_agent_mesh/evaluation/shared/constants.py +47 -0
  124. solace_agent_mesh/evaluation/shared/exceptions.py +50 -0
  125. solace_agent_mesh/evaluation/shared/helpers.py +35 -0
  126. solace_agent_mesh/evaluation/shared/test_case_loader.py +167 -0
  127. solace_agent_mesh/evaluation/shared/test_suite_loader.py +280 -0
  128. solace_agent_mesh/evaluation/subscriber.py +111 -232
  129. solace_agent_mesh/evaluation/summary_builder.py +227 -117
  130. solace_agent_mesh/gateway/base/app.py +1 -1
  131. solace_agent_mesh/gateway/base/component.py +8 -1
  132. solace_agent_mesh/gateway/http_sse/alembic/versions/20251015_add_session_performance_indexes.py +70 -0
  133. solace_agent_mesh/gateway/http_sse/component.py +98 -2
  134. solace_agent_mesh/gateway/http_sse/dependencies.py +4 -4
  135. solace_agent_mesh/gateway/http_sse/main.py +2 -1
  136. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +12 -13
  137. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +15 -18
  138. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +25 -18
  139. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +30 -26
  140. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +35 -44
  141. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +4 -3
  142. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +95 -203
  143. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +4 -3
  144. solace_agent_mesh/gateway/http_sse/routers/sessions.py +2 -2
  145. solace_agent_mesh/gateway/http_sse/routers/tasks.py +33 -41
  146. solace_agent_mesh/gateway/http_sse/routers/visualization.py +17 -11
  147. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +4 -4
  148. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +51 -43
  149. solace_agent_mesh/gateway/http_sse/services/session_service.py +20 -20
  150. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +8 -8
  151. solace_agent_mesh/gateway/http_sse/shared/base_repository.py +45 -71
  152. solace_agent_mesh/gateway/http_sse/shared/types.py +0 -18
  153. solace_agent_mesh/templates/gateway_config_template.yaml +0 -5
  154. solace_agent_mesh/templates/logging_config_template.ini +10 -6
  155. solace_agent_mesh/templates/plugin_gateway_config_template.yaml +0 -3
  156. solace_agent_mesh/templates/shared_config.yaml +40 -0
  157. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.0.dist-info}/METADATA +47 -21
  158. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.0.dist-info}/RECORD +162 -141
  159. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.e49689dd.js +0 -1
  160. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.39d5851d.js +0 -1
  161. solace_agent_mesh/assets/docs/assets/js/71da7b71.804d6567.js +0 -1
  162. solace_agent_mesh/assets/docs/assets/js/77cf947d.64c9bd6c.js +0 -1
  163. solace_agent_mesh/assets/docs/assets/js/9e9d0a82.dd810042.js +0 -1
  164. solace_agent_mesh/assets/docs/assets/js/db924877.cbc66f02.js +0 -1
  165. solace_agent_mesh/assets/docs/assets/js/de915948.139b4b9c.js +0 -1
  166. solace_agent_mesh/assets/docs/assets/js/e6f9706b.582a78ca.js +0 -1
  167. solace_agent_mesh/assets/docs/assets/js/f284c35a.5766a13d.js +0 -1
  168. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.9c0297a6.js +0 -1
  169. solace_agent_mesh/assets/docs/assets/js/runtime~main.18dc45dd.js +0 -1
  170. solace_agent_mesh/assets/docs/lunr-index-1760121512891.json +0 -1
  171. solace_agent_mesh/assets/docs/search-doc-1760121512891.json +0 -1
  172. solace_agent_mesh/client/webui/frontend/static/assets/main-2nd1gbaH.js +0 -339
  173. solace_agent_mesh/client/webui/frontend/static/assets/main-DoKXctCM.css +0 -1
  174. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-BNuqpWDc.js +0 -98
  175. solace_agent_mesh/evaluation/config_loader.py +0 -657
  176. solace_agent_mesh/evaluation/test_case_loader.py +0 -714
  177. /solace_agent_mesh/assets/docs/assets/js/{main.bd3c34f3.js.LICENSE.txt → main.20feee82.js.LICENSE.txt} +0 -0
  178. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.0.dist-info}/WHEEL +0 -0
  179. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.0.dist-info}/entry_points.txt +0 -0
  180. {solace_agent_mesh-1.5.1.dist-info → solace_agent_mesh-1.6.0.dist-info}/licenses/LICENSE +0 -0
@@ -6,22 +6,17 @@ from sqlalchemy.orm import Session as DBSession
6
6
 
7
7
  from ..shared.base_repository import PaginatedRepository
8
8
  from ..shared.pagination import PaginationParams
9
- from ..shared.types import PaginationInfo, SessionId, UserId
9
+ from ..shared.types import SessionId, UserId
10
10
  from .entities import Session
11
11
  from .interfaces import ISessionRepository
12
- from .models import (
13
- SessionModel,
14
- CreateSessionModel,
15
- UpdateSessionModel,
16
- )
12
+ from .models import CreateSessionModel, SessionModel, UpdateSessionModel
17
13
 
18
14
 
19
15
  class SessionRepository(PaginatedRepository[SessionModel, Session], ISessionRepository):
20
16
  """SQLAlchemy implementation of session repository using BaseRepository."""
21
17
 
22
- def __init__(self, db: DBSession):
18
+ def __init__(self):
23
19
  super().__init__(SessionModel, Session)
24
- self.db = db
25
20
 
26
21
  @property
27
22
  def entity_name(self) -> str:
@@ -29,29 +24,30 @@ class SessionRepository(PaginatedRepository[SessionModel, Session], ISessionRepo
29
24
  return "session"
30
25
 
31
26
  def find_by_user(
32
- self, user_id: UserId, pagination: PaginationParams | None = None
27
+ self, session: DBSession, user_id: UserId, pagination: PaginationParams | None = None
33
28
  ) -> list[Session]:
34
29
  """Find all sessions for a specific user."""
35
- query = self.db.query(SessionModel).filter(SessionModel.user_id == user_id)
30
+ query = session.query(SessionModel).filter(SessionModel.user_id == user_id)
36
31
  query = query.order_by(SessionModel.updated_time.desc())
37
32
 
38
33
  if pagination:
39
- offset = (pagination.page_number - 1) * pagination.page_size
40
- query = query.offset(offset).limit(pagination.page_size)
34
+ query = query.offset(pagination.offset).limit(pagination.page_size)
41
35
 
42
36
  models = query.all()
43
37
  return [Session.model_validate(model) for model in models]
44
38
 
45
- def count_by_user(self, user_id: UserId) -> int:
39
+ def count_by_user(self, session: DBSession, user_id: UserId) -> int:
46
40
  """Count total sessions for a specific user."""
47
- return self.db.query(SessionModel).filter(SessionModel.user_id == user_id).count()
41
+ return (
42
+ session.query(SessionModel).filter(SessionModel.user_id == user_id).count()
43
+ )
48
44
 
49
45
  def find_user_session(
50
- self, session_id: SessionId, user_id: UserId
46
+ self, session: DBSession, session_id: SessionId, user_id: UserId
51
47
  ) -> Session | None:
52
48
  """Find a specific session belonging to a user."""
53
49
  model = (
54
- self.db.query(SessionModel)
50
+ session.query(SessionModel)
55
51
  .filter(
56
52
  SessionModel.id == session_id,
57
53
  SessionModel.user_id == user_id,
@@ -60,9 +56,11 @@ class SessionRepository(PaginatedRepository[SessionModel, Session], ISessionRepo
60
56
  )
61
57
  return Session.model_validate(model) if model else None
62
58
 
63
- def save(self, session: Session) -> Session:
59
+ def save(self, db_session: DBSession, session: Session) -> Session:
64
60
  """Save or update a session."""
65
- existing_model = self.db.query(SessionModel).filter(SessionModel.id == session.id).first()
61
+ existing_model = (
62
+ db_session.query(SessionModel).filter(SessionModel.id == session.id).first()
63
+ )
66
64
 
67
65
  if existing_model:
68
66
  update_model = UpdateSessionModel(
@@ -70,7 +68,9 @@ class SessionRepository(PaginatedRepository[SessionModel, Session], ISessionRepo
70
68
  agent_id=session.agent_id,
71
69
  updated_time=session.updated_time,
72
70
  )
73
- return self.update(self.db, session.id, update_model.model_dump(exclude_none=True))
71
+ return self.update(
72
+ db_session, session.id, update_model.model_dump(exclude_none=True)
73
+ )
74
74
  else:
75
75
  create_model = CreateSessionModel(
76
76
  id=session.id,
@@ -80,19 +80,23 @@ class SessionRepository(PaginatedRepository[SessionModel, Session], ISessionRepo
80
80
  created_time=session.created_time,
81
81
  updated_time=session.updated_time,
82
82
  )
83
- return self.create(self.db, create_model.model_dump())
83
+ return self.create(db_session, create_model.model_dump())
84
84
 
85
- def delete(self, session_id: SessionId, user_id: UserId) -> bool:
85
+ def delete(self, db_session: DBSession, session_id: SessionId, user_id: UserId) -> bool:
86
86
  """Delete a session belonging to a user."""
87
87
  # Check if session belongs to user first
88
- session_model = self.db.query(SessionModel).filter(
89
- SessionModel.id == session_id,
90
- SessionModel.user_id == user_id,
91
- ).first()
88
+ session_model = (
89
+ db_session.query(SessionModel)
90
+ .filter(
91
+ SessionModel.id == session_id,
92
+ SessionModel.user_id == user_id,
93
+ )
94
+ .first()
95
+ )
92
96
 
93
97
  if not session_model:
94
98
  return False
95
99
 
96
100
  # Use BaseRepository delete method
97
- super().delete(self.db, session_id)
101
+ super().delete(db_session, session_id)
98
102
  return True
@@ -4,7 +4,8 @@ Task repository implementation using SQLAlchemy.
4
4
 
5
5
  from sqlalchemy.orm import Session as DBSession
6
6
 
7
- from ..shared.types import PaginationInfo, PaginationParams, UserId
7
+ from ..shared.pagination import PaginationParams
8
+ from ..shared.types import UserId
8
9
  from .entities import Task, TaskEvent
9
10
  from .interfaces import ITaskRepository
10
11
  from .models import TaskEventModel, TaskModel
@@ -13,15 +14,11 @@ from .models import TaskEventModel, TaskModel
13
14
  class TaskRepository(ITaskRepository):
14
15
  """SQLAlchemy implementation of task repository."""
15
16
 
16
- def __init__(self, db: DBSession):
17
- self.db = db
18
-
19
- def save_task(self, task: Task) -> Task:
17
+ def save_task(self, session: DBSession, task: Task) -> Task:
20
18
  """Create or update a task."""
21
- model = self.db.query(TaskModel).filter(TaskModel.id == task.id).first()
19
+ model = session.query(TaskModel).filter(TaskModel.id == task.id).first()
22
20
 
23
21
  if model:
24
- # Update existing
25
22
  model.end_time = task.end_time
26
23
  model.status = task.status
27
24
  model.total_input_tokens = task.total_input_tokens
@@ -29,7 +26,6 @@ class TaskRepository(ITaskRepository):
29
26
  model.total_cached_input_tokens = task.total_cached_input_tokens
30
27
  model.token_usage_details = task.token_usage_details
31
28
  else:
32
- # Create new
33
29
  model = TaskModel(
34
30
  id=task.id,
35
31
  user_id=task.user_id,
@@ -42,13 +38,13 @@ class TaskRepository(ITaskRepository):
42
38
  total_cached_input_tokens=task.total_cached_input_tokens,
43
39
  token_usage_details=task.token_usage_details,
44
40
  )
45
- self.db.add(model)
41
+ session.add(model)
46
42
 
47
- self.db.commit()
48
- self.db.refresh(model)
43
+ session.flush()
44
+ session.refresh(model)
49
45
  return self._task_model_to_entity(model)
50
46
 
51
- def save_event(self, event: TaskEvent) -> TaskEvent:
47
+ def save_event(self, session: DBSession, event: TaskEvent) -> TaskEvent:
52
48
  """Save a task event."""
53
49
  model = TaskEventModel(
54
50
  id=event.id,
@@ -59,26 +55,26 @@ class TaskRepository(ITaskRepository):
59
55
  direction=event.direction,
60
56
  payload=event.payload,
61
57
  )
62
- self.db.add(model)
63
- self.db.commit()
64
- self.db.refresh(model)
58
+ session.add(model)
59
+ session.flush()
60
+ session.refresh(model)
65
61
  return self._event_model_to_entity(model)
66
62
 
67
- def find_by_id(self, task_id: str) -> Task | None:
63
+ def find_by_id(self, session: DBSession, task_id: str) -> Task | None:
68
64
  """Find a task by its ID."""
69
- model = self.db.query(TaskModel).filter(TaskModel.id == task_id).first()
65
+ model = session.query(TaskModel).filter(TaskModel.id == task_id).first()
70
66
  return self._task_model_to_entity(model) if model else None
71
67
 
72
68
  def find_by_id_with_events(
73
- self, task_id: str
69
+ self, session: DBSession, task_id: str
74
70
  ) -> tuple[Task, list[TaskEvent]] | None:
75
71
  """Find a task with all its events."""
76
- task_model = self.db.query(TaskModel).filter(TaskModel.id == task_id).first()
72
+ task_model = session.query(TaskModel).filter(TaskModel.id == task_id).first()
77
73
  if not task_model:
78
74
  return None
79
75
 
80
76
  event_models = (
81
- self.db.query(TaskEventModel)
77
+ session.query(TaskEventModel)
82
78
  .filter(TaskEventModel.task_id == task_id)
83
79
  .order_by(TaskEventModel.created_time.asc())
84
80
  .all()
@@ -90,36 +86,31 @@ class TaskRepository(ITaskRepository):
90
86
 
91
87
  def search(
92
88
  self,
89
+ session: DBSession,
93
90
  user_id: UserId,
94
91
  start_date: int | None = None,
95
92
  end_date: int | None = None,
96
- search_query: str | None = None,
97
93
  pagination: PaginationParams | None = None,
98
94
  ) -> list[Task]:
99
95
  """Search for tasks with filters."""
100
- query = self.db.query(TaskModel)
101
- if user_id != "*": # Allow wildcard for admin/system searches
96
+ query = session.query(TaskModel)
97
+ if user_id != "*":
102
98
  query = query.filter(TaskModel.user_id == user_id)
103
99
 
104
100
  if start_date:
105
101
  query = query.filter(TaskModel.start_time >= start_date)
106
102
  if end_date:
107
103
  query = query.filter(TaskModel.start_time <= end_date)
108
- if search_query:
109
- query = query.filter(
110
- TaskModel.initial_request_text.ilike(f"%{search_query}%")
111
- )
112
104
 
113
105
  query = query.order_by(TaskModel.start_time.desc())
114
106
 
115
107
  if pagination:
116
- offset = (pagination.page - 1) * pagination.page_size
117
- query = query.offset(offset).limit(pagination.page_size)
108
+ query = query.offset(pagination.offset).limit(pagination.page_size)
118
109
 
119
110
  models = query.all()
120
111
  return [self._task_model_to_entity(model) for model in models]
121
112
 
122
- def delete_tasks_older_than(self, cutoff_time_ms: int, batch_size: int) -> int:
113
+ def delete_tasks_older_than(self, session: DBSession, cutoff_time_ms: int, batch_size: int) -> int:
123
114
  """
124
115
  Delete tasks (and their events via cascade) older than the cutoff time.
125
116
  Uses batch deletion to avoid long-running transactions.
@@ -130,38 +121,38 @@ class TaskRepository(ITaskRepository):
130
121
 
131
122
  Returns:
132
123
  Total number of tasks deleted
124
+
125
+ Note:
126
+ This method commits each batch internally due to the nature of batch processing.
127
+ Each batch is an atomic operation to prevent long-running transactions.
133
128
  """
134
129
  total_deleted = 0
135
-
130
+
136
131
  while True:
137
- # Find a batch of task IDs to delete
138
132
  task_ids_to_delete = (
139
- self.db.query(TaskModel.id)
133
+ session.query(TaskModel.id)
140
134
  .filter(TaskModel.start_time < cutoff_time_ms)
141
135
  .limit(batch_size)
142
136
  .all()
143
137
  )
144
-
138
+
145
139
  if not task_ids_to_delete:
146
140
  break
147
-
148
- # Extract IDs from the result tuples
141
+
149
142
  ids = [task_id[0] for task_id in task_ids_to_delete]
150
-
151
- # Delete this batch
143
+
152
144
  deleted_count = (
153
- self.db.query(TaskModel)
145
+ session.query(TaskModel)
154
146
  .filter(TaskModel.id.in_(ids))
155
147
  .delete(synchronize_session=False)
156
148
  )
157
-
158
- self.db.commit()
149
+
150
+ session.commit()
159
151
  total_deleted += deleted_count
160
-
161
- # If we deleted fewer than batch_size, we're done
152
+
162
153
  if deleted_count < batch_size:
163
154
  break
164
-
155
+
165
156
  return total_deleted
166
157
 
167
158
  def _task_model_to_entity(self, model: TaskModel) -> Task:
@@ -1,14 +1,15 @@
1
1
  """
2
- API Router for agent discovery.
2
+ API Router for agent discovery and management.
3
3
  """
4
4
 
5
5
  import logging
6
6
  from fastapi import APIRouter, Depends, HTTPException, status
7
- from typing import List
7
+ from typing import Dict, List
8
8
 
9
9
  from ....common.agent_registry import AgentRegistry
10
10
  from a2a.types import AgentCard
11
- from ..dependencies import get_agent_registry
11
+ from ..dependencies import get_agent_registry, get_sac_component
12
+ from ..component import WebUIBackendComponent
12
13
 
13
14
  log = logging.getLogger(__name__)
14
15