solace-agent-mesh 1.6.2__py3-none-any.whl → 1.7.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 (245) hide show
  1. solace_agent_mesh/agent/adk/adk_llm.txt +12 -18
  2. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +1 -1
  3. solace_agent_mesh/agent/adk/callbacks.py +138 -20
  4. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +2 -0
  5. solace_agent_mesh/agent/adk/models/lite_llm.py +38 -5
  6. solace_agent_mesh/agent/adk/models/models_llm.txt +82 -35
  7. solace_agent_mesh/agent/adk/runner.py +9 -0
  8. solace_agent_mesh/agent/adk/services.py +3 -3
  9. solace_agent_mesh/agent/adk/stream_parser.py +6 -1
  10. solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
  11. solace_agent_mesh/agent/agent_llm.txt +61 -70
  12. solace_agent_mesh/agent/protocol/event_handlers.py +29 -1
  13. solace_agent_mesh/agent/protocol/protocol_llm.txt +1 -1
  14. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +190 -0
  15. solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
  16. solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
  17. solace_agent_mesh/agent/sac/app.py +22 -0
  18. solace_agent_mesh/agent/sac/component.py +76 -40
  19. solace_agent_mesh/agent/sac/sac_llm.txt +1 -1
  20. solace_agent_mesh/agent/sac/task_execution_context.py +21 -0
  21. solace_agent_mesh/agent/testing/testing_llm.txt +2 -1
  22. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +13 -148
  23. solace_agent_mesh/agent/tools/dynamic_tool.py +2 -0
  24. solace_agent_mesh/agent/tools/tools_llm.txt +93 -80
  25. solace_agent_mesh/agent/tools/tools_llm_detail.txt +3 -2
  26. solace_agent_mesh/agent/utils/artifact_helpers.py +4 -0
  27. solace_agent_mesh/agent/utils/utils_llm.txt +16 -2
  28. solace_agent_mesh/assets/docs/404.html +3 -3
  29. solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +1 -0
  30. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +1 -0
  31. solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +1 -0
  32. solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +1 -0
  34. solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +1 -0
  35. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
  36. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +1 -0
  37. solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
  38. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
  39. solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
  40. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
  41. solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
  42. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +1 -0
  43. solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +1 -0
  45. solace_agent_mesh/assets/docs/assets/js/{ab9708a8.3e6dd091.js → ab9708a8.245ae0ef.js} +1 -1
  46. solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
  47. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/{e6f9706b.e74a984d.js → e6f9706b.045d0fa1.js} +1 -1
  56. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/main.e6488e8b.js +2 -0
  60. solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +1 -0
  61. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
  64. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
  65. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +18 -4
  66. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
  67. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
  68. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +5 -5
  69. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
  70. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
  71. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
  72. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +196 -0
  73. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +4 -4
  74. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +5 -5
  75. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +6 -7
  76. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
  77. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +47 -0
  78. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +4 -4
  79. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +4 -4
  80. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
  81. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +160 -169
  82. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
  83. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
  84. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +4 -4
  85. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +4 -4
  86. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
  87. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
  88. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +5 -5
  89. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +4 -4
  90. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
  91. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
  92. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
  93. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
  94. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
  95. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
  96. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +59 -0
  97. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +62 -0
  98. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +10 -6
  99. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +4 -4
  100. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +24 -29
  101. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
  102. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +27 -4
  103. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
  104. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +4 -4
  105. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +5 -4
  106. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  107. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
  108. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +290 -0
  109. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +9 -9
  110. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +4 -4
  111. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +4 -4
  112. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +4 -4
  113. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +4 -4
  114. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
  115. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
  116. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
  117. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
  118. solace_agent_mesh/assets/docs/lunr-index-1762189824009.json +1 -0
  119. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  120. solace_agent_mesh/assets/docs/search-doc-1762189824009.json +1 -0
  121. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  122. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  123. solace_agent_mesh/cli/__init__.py +1 -1
  124. solace_agent_mesh/cli/commands/docs_cmd.py +4 -1
  125. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +1 -1
  126. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-D4_RMYRh.js → authCallback-tcIFZLis.js} +1 -1
  127. solace_agent_mesh/client/webui/frontend/static/assets/{client-UZ3qU6Bq.js → client-CRYdKo2Q.js} +3 -3
  128. solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +1 -0
  129. solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +353 -0
  130. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CINwxvwV.js +470 -0
  131. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  132. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  133. solace_agent_mesh/common/a2a/a2a_llm.txt +13 -20
  134. solace_agent_mesh/common/a2a/protocol.py +5 -0
  135. solace_agent_mesh/common/a2a/types.py +1 -0
  136. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +49 -11
  137. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
  138. solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
  139. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +26 -9
  140. solace_agent_mesh/common/common_llm.txt +13 -34
  141. solace_agent_mesh/common/data_parts.py +20 -4
  142. solace_agent_mesh/common/middleware/middleware_llm.txt +1 -1
  143. solace_agent_mesh/common/sac/sac_llm.txt +1 -1
  144. solace_agent_mesh/common/sam_events/sam_events_llm.txt +1 -1
  145. solace_agent_mesh/common/services/employee_service.py +1 -1
  146. solace_agent_mesh/common/services/providers/providers_llm.txt +3 -2
  147. solace_agent_mesh/common/services/services_llm.txt +9 -4
  148. solace_agent_mesh/common/utils/embeds/constants.py +1 -0
  149. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
  150. solace_agent_mesh/common/utils/embeds/modifiers.py +2 -1
  151. solace_agent_mesh/common/utils/embeds/resolver.py +58 -6
  152. solace_agent_mesh/common/utils/embeds/types.py +8 -0
  153. solace_agent_mesh/common/utils/utils_llm.txt +5 -6
  154. solace_agent_mesh/core_a2a/core_a2a_llm.txt +1 -1
  155. solace_agent_mesh/gateway/adapter/__init__.py +1 -0
  156. solace_agent_mesh/gateway/adapter/base.py +143 -0
  157. solace_agent_mesh/gateway/adapter/types.py +221 -0
  158. solace_agent_mesh/gateway/base/app.py +29 -2
  159. solace_agent_mesh/gateway/base/base_llm.txt +10 -8
  160. solace_agent_mesh/gateway/base/component.py +573 -142
  161. solace_agent_mesh/gateway/gateway_llm.txt +55 -59
  162. solace_agent_mesh/gateway/generic/__init__.py +1 -0
  163. solace_agent_mesh/gateway/generic/app.py +50 -0
  164. solace_agent_mesh/gateway/generic/component.py +650 -0
  165. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +99 -49
  166. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +92 -0
  167. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
  168. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +150 -0
  169. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
  170. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
  171. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +26 -20
  172. solace_agent_mesh/gateway/http_sse/app.py +19 -14
  173. solace_agent_mesh/gateway/http_sse/component.py +150 -118
  174. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +1 -1
  175. solace_agent_mesh/gateway/http_sse/dependencies.py +21 -3
  176. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +8 -8
  177. solace_agent_mesh/gateway/http_sse/main.py +55 -14
  178. solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
  179. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +56 -98
  180. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
  181. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
  182. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +23 -1
  183. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
  184. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +112 -4
  185. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -1
  186. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +51 -60
  187. solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
  188. solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
  189. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +7 -1
  190. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
  191. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
  192. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +125 -157
  193. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +269 -8
  194. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +143 -51
  195. solace_agent_mesh/gateway/http_sse/routers/config.py +69 -0
  196. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +198 -94
  197. solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
  198. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +68 -18
  199. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +13 -0
  200. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +30 -0
  201. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +51 -35
  202. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +2 -0
  203. solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
  204. solace_agent_mesh/gateway/http_sse/routers/projects.py +542 -0
  205. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +9 -11
  206. solace_agent_mesh/gateway/http_sse/routers/sessions.py +154 -3
  207. solace_agent_mesh/gateway/http_sse/routers/tasks.py +296 -4
  208. solace_agent_mesh/gateway/http_sse/services/project_service.py +403 -0
  209. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +16 -10
  210. solace_agent_mesh/gateway/http_sse/services/session_service.py +178 -6
  211. solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +2 -3
  212. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +48 -14
  213. solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
  214. {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/METADATA +3 -5
  215. {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/RECORD +219 -176
  216. solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
  217. solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +0 -1
  218. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
  219. solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
  220. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
  221. solace_agent_mesh/assets/docs/assets/js/631738c7.7c4594c9.js +0 -1
  222. solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
  223. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
  224. solace_agent_mesh/assets/docs/assets/js/71da7b71.ddbdfbe2.js +0 -1
  225. solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +0 -1
  226. solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +0 -1
  227. solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
  228. solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
  229. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
  230. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
  231. solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
  232. solace_agent_mesh/assets/docs/assets/js/e92d0134.4f395c6b.js +0 -1
  233. solace_agent_mesh/assets/docs/assets/js/f284c35a.720d2ef2.js +0 -1
  234. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
  235. solace_agent_mesh/assets/docs/assets/js/main.d1643f0b.js +0 -2
  236. solace_agent_mesh/assets/docs/assets/js/runtime~main.97f920d4.js +0 -1
  237. solace_agent_mesh/assets/docs/lunr-index-1761663789856.json +0 -1
  238. solace_agent_mesh/assets/docs/search-doc-1761663789856.json +0 -1
  239. solace_agent_mesh/client/webui/frontend/static/assets/main--3yJYl7S.css +0 -1
  240. solace_agent_mesh/client/webui/frontend/static/assets/main-DojKHS49.js +0 -342
  241. solace_agent_mesh/client/webui/frontend/static/assets/vendor-DSqhjwq_.js +0 -405
  242. /solace_agent_mesh/assets/docs/assets/js/{main.d1643f0b.js.LICENSE.txt → main.e6488e8b.js.LICENSE.txt} +0 -0
  243. {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/WHEEL +0 -0
  244. {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/entry_points.txt +0 -0
  245. {solace_agent_mesh-1.6.2.dist-info → solace_agent_mesh-1.7.0.dist-info}/licenses/LICENSE +0 -0
@@ -1,9 +1,14 @@
1
1
  import logging
2
2
  import os
3
3
  from pathlib import Path
4
- from typing import TYPE_CHECKING
5
4
 
6
5
  import httpx
6
+ import sqlalchemy as sa
7
+ from fastapi import FastAPI, HTTPException
8
+ from fastapi import Request as FastAPIRequest
9
+ from fastapi import status
10
+ from typing import TYPE_CHECKING
11
+
7
12
  import sqlalchemy as sa
8
13
  from a2a.types import InternalError, JSONRPCError
9
14
  from a2a.types import JSONRPCResponse as A2AJSONRPCResponse
@@ -18,23 +23,35 @@ from fastapi.responses import JSONResponse
18
23
  from starlette.middleware.sessions import SessionMiddleware
19
24
  from starlette.staticfiles import StaticFiles
20
25
 
26
+ from .routers.sessions import router as session_router
27
+ from .routers.tasks import router as task_router
28
+ from .routers.users import router as user_router
21
29
  from ...common import a2a
22
30
  from ...gateway.http_sse import dependencies
23
- from ...gateway.http_sse.routers import (
31
+ from .routers import (
24
32
  agent_cards,
25
33
  artifacts,
26
34
  auth,
27
35
  config,
36
+ feedback,
28
37
  people,
29
38
  sse,
30
- tasks,
31
39
  visualization,
32
- feedback,
40
+ projects,
33
41
  )
34
42
  from .routers.sessions import router as session_router
35
43
  from .routers.tasks import router as task_router
36
44
  from .routers.users import router as user_router
37
45
 
46
+ from alembic import command
47
+ from alembic.config import Config
48
+
49
+ from a2a.types import InternalError, InvalidRequestError, JSONRPCError
50
+ from a2a.types import JSONRPCResponse as A2AJSONRPCResponse
51
+ from ...common import a2a
52
+ from ...gateway.http_sse import dependencies
53
+
54
+
38
55
  if TYPE_CHECKING:
39
56
  from gateway.http_sse.component import WebUIBackendComponent
40
57
 
@@ -453,17 +470,32 @@ def _run_enterprise_migrations(
453
470
  raise RuntimeError(f"Enterprise database migration failed: {e}") from e
454
471
 
455
472
 
456
- def _setup_database(component: "WebUIBackendComponent", database_url: str) -> None:
473
+ def _setup_database(
474
+ component: "WebUIBackendComponent",
475
+ database_url: str,
476
+ platform_database_url: str = None
477
+ ) -> None:
457
478
  """
458
- Initialize database connection and run all required migrations.
459
- This sets up both community and enterprise database schemas.
479
+ Initialize database connections and run all required migrations.
480
+ Sets up both runtime and platform database schemas.
481
+
482
+ Args:
483
+ component: WebUIBackendComponent instance
484
+ database_url: Runtime database URL (sessions, tasks, chat) - REQUIRED
485
+ platform_database_url: Platform database URL (agents, connectors, deployments).
486
+ If None, platform features will be unavailable.
460
487
  """
461
488
  dependencies.init_database(database_url)
462
489
  log.info("Persistence enabled - sessions will be stored in database")
463
490
  log.info("Running database migrations...")
464
491
 
465
492
  _run_community_migrations(database_url)
466
- _run_enterprise_migrations(component, database_url)
493
+
494
+ if platform_database_url:
495
+ log.info("Platform database configured - running migrations")
496
+ _run_enterprise_migrations(component, platform_database_url)
497
+ else:
498
+ log.info("No platform database configured - skipping platform migrations")
467
499
 
468
500
 
469
501
  def _get_app_config(component: "WebUIBackendComponent") -> dict:
@@ -498,12 +530,20 @@ def _create_api_config(app_config: dict, database_url: str) -> dict:
498
530
  }
499
531
 
500
532
 
501
- def setup_dependencies(component: "WebUIBackendComponent", database_url: str = None):
533
+ def setup_dependencies(
534
+ component: "WebUIBackendComponent",
535
+ database_url: str = None,
536
+ platform_database_url: str = None
537
+ ):
502
538
  """
503
- This function initializes the simplified architecture while maintaining full
504
- backward compatibility with existing API contracts.
539
+ Initialize dependencies for both runtime and platform databases.
505
540
 
506
- If database_url is None, runs in compatibility mode with in-memory sessions.
541
+ Args:
542
+ component: WebUIBackendComponent instance
543
+ database_url: Runtime database URL (sessions, tasks, chat).
544
+ If None, runs in compatibility mode with in-memory sessions.
545
+ platform_database_url: Platform database URL (agents, connectors, deployments).
546
+ If None, platform features will be unavailable (returns 501).
507
547
 
508
548
  This function is idempotent and safe to call multiple times.
509
549
  """
@@ -516,7 +556,7 @@ def setup_dependencies(component: "WebUIBackendComponent", database_url: str = N
516
556
  dependencies.set_component_instance(component)
517
557
 
518
558
  if database_url:
519
- _setup_database(component, database_url)
559
+ _setup_database(component, database_url, platform_database_url)
520
560
  else:
521
561
  log.warning(
522
562
  "No database URL provided - using in-memory session storage (data not persisted across restarts)"
@@ -564,7 +604,7 @@ def _setup_routers() -> None:
564
604
  app.include_router(user_router, prefix=f"{api_prefix}/users", tags=["Users"])
565
605
  app.include_router(config.router, prefix=api_prefix, tags=["Config"])
566
606
  app.include_router(agent_cards.router, prefix=api_prefix, tags=["Agent Cards"])
567
- app.include_router(tasks.router, prefix=api_prefix, tags=["Tasks"])
607
+ app.include_router(task_router, prefix=api_prefix, tags=["Tasks"])
568
608
  app.include_router(sse.router, prefix=f"{api_prefix}/sse", tags=["SSE"])
569
609
  app.include_router(
570
610
  artifacts.router, prefix=f"{api_prefix}/artifacts", tags=["Artifacts"]
@@ -576,6 +616,7 @@ def _setup_routers() -> None:
576
616
  )
577
617
  app.include_router(people.router, prefix=api_prefix, tags=["People"])
578
618
  app.include_router(auth.router, prefix=api_prefix, tags=["Auth"])
619
+ app.include_router(projects.router, prefix=api_prefix, tags=["Projects"])
579
620
  app.include_router(feedback.router, prefix=api_prefix, tags=["Feedback"])
580
621
  log.info("Legacy routers mounted for endpoints not yet migrated")
581
622
 
@@ -3,10 +3,20 @@ Repository layer containing all data access logic organized by entity type.
3
3
  """
4
4
 
5
5
  # Interfaces
6
- from .interfaces import ISessionRepository
6
+ from .interfaces import (
7
+ IChatTaskRepository,
8
+ IFeedbackRepository,
9
+ IProjectRepository,
10
+ ISessionRepository,
11
+ ITaskRepository,
12
+ )
7
13
 
8
14
  # Implementations
15
+ from .chat_task_repository import ChatTaskRepository
16
+ from .feedback_repository import FeedbackRepository
17
+ from .project_repository import ProjectRepository
9
18
  from .session_repository import SessionRepository
19
+ from .task_repository import TaskRepository
10
20
 
11
21
  # Entities (re-exported for convenience)
12
22
  from .entities.session import Session
@@ -17,9 +27,17 @@ from .models.session_model import SessionModel
17
27
 
18
28
  __all__ = [
19
29
  # Interfaces
30
+ "IChatTaskRepository",
31
+ "IFeedbackRepository",
32
+ "IProjectRepository",
20
33
  "ISessionRepository",
34
+ "ITaskRepository",
21
35
  # Implementations
36
+ "ChatTaskRepository",
37
+ "FeedbackRepository",
38
+ "ProjectRepository",
22
39
  "SessionRepository",
40
+ "TaskRepository",
23
41
  # Entities
24
42
  "Session",
25
43
  # Models
@@ -1,29 +1,74 @@
1
1
  # DEVELOPER GUIDE: entities
2
2
 
3
3
  ## Quick Summary
4
- The entities directory contains domain entities for the repository layer, providing core business objects for managing chat sessions, messages, tasks, feedback, and events with built-in validation and business logic.
4
+ The entities directory contains domain entities for the repository layer, providing core business objects for managing chat sessions, tasks, feedback, and events with built-in validation and business logic.
5
5
 
6
6
  ## Files Overview
7
- - `__init__.py` - Exports the main domain entities (Feedback, Message, Session, SessionHistory, Task, TaskEvent)
7
+ - `__init__.py` - Exports the main domain entities (ChatTask, Feedback, Session, Task, TaskEvent)
8
+ - `chat_task.py` - ChatTask entity for managing chat conversations with JSON validation
8
9
  - `feedback.py` - Feedback entity for user ratings and comments on tasks
9
- - `message.py` - Message entity with content validation and sender type checking
10
10
  - `session.py` - Session entity with name management and access control
11
- - `session_history.py` - Composite entity combining sessions with their message history
12
- - `task.py` - Task entity for tracking user tasks and their status with token usage
13
- - `task_event.py` - Task event entity for tracking events related to tasks
11
+ - `task.py` - Task entity for tracking user tasks with token usage metrics
12
+ - `task_event.py` - TaskEvent entity for tracking events related to tasks
14
13
 
15
14
  ## Developer API Reference
16
15
 
17
16
  ### __init__.py
18
17
  **Purpose:** Provides centralized imports for all domain entities
19
- **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Feedback, Message, Session, SessionHistory, Task, TaskEvent`
18
+ **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import ChatTask, Feedback, Session, Task, TaskEvent`
19
+
20
+ ### chat_task.py
21
+ **Purpose:** Defines the ChatTask domain entity for managing chat conversations with JSON validation
22
+ **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import ChatTask`
23
+
24
+ **Classes:**
25
+ - `ChatTask(id: str, session_id: str, user_id: str, message_bubbles: str, created_time: int, user_message: str | None = None, task_metadata: str | None = None, updated_time: int | None = None)` - ChatTask domain entity with business logic
26
+ - `add_feedback(feedback_type: str, feedback_text: str | None = None) -> None` - Add or update feedback for this task
27
+ - `get_feedback() -> dict[str, Any] | None` - Get feedback for this task
28
+ - `id: str` - Unique task identifier
29
+ - `session_id: str` - Associated session identifier
30
+ - `user_id: str` - User who owns the task
31
+ - `user_message: str | None` - Optional user message
32
+ - `message_bubbles: str` - JSON string containing message bubbles (must be non-empty JSON array)
33
+ - `task_metadata: str | None` - Optional JSON string for task metadata
34
+ - `created_time: int` - Task creation timestamp
35
+ - `updated_time: int | None` - Last update timestamp
36
+
37
+ **Usage Examples:**
38
+ ```python
39
+ from solace_agent_mesh.gateway.http_sse.repository.entities import ChatTask
40
+ import json
41
+
42
+ # Create a chat task
43
+ message_bubbles = json.dumps([
44
+ {"type": "user", "content": "Hello"},
45
+ {"type": "agent", "content": "Hi there!"}
46
+ ])
47
+
48
+ chat_task = ChatTask(
49
+ id="chat_123",
50
+ session_id="session_456",
51
+ user_id="user_789",
52
+ user_message="Hello",
53
+ message_bubbles=message_bubbles,
54
+ created_time=1640995200000
55
+ )
56
+
57
+ # Add feedback
58
+ chat_task.add_feedback("positive", "Great response!")
59
+
60
+ # Get feedback
61
+ feedback = chat_task.get_feedback()
62
+ if feedback:
63
+ print(f"Feedback type: {feedback['type']}")
64
+ ```
20
65
 
21
66
  ### feedback.py
22
67
  **Purpose:** Defines the Feedback domain entity for user ratings and comments
23
68
  **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Feedback`
24
69
 
25
70
  **Classes:**
26
- - `Feedback(id: str, session_id: str, task_id: str, user_id: str, rating: str, comment: str | None = None, created_time: int)` - Feedback domain entity
71
+ - `Feedback(id: str, session_id: str, task_id: str, user_id: str, rating: str, created_time: int, comment: str | None = None)` - Feedback domain entity
27
72
  - `id: str` - Unique feedback identifier
28
73
  - `session_id: str` - Associated session identifier
29
74
  - `task_id: str` - Associated task identifier
@@ -48,54 +93,12 @@ feedback = Feedback(
48
93
  )
49
94
  ```
50
95
 
51
- ### message.py
52
- **Purpose:** Defines the Message domain entity with business logic for chat messages
53
- **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Message`
54
-
55
- **Classes:**
56
- - `Message(id: MessageId, session_id: SessionId, message: str, sender_type: SenderType, sender_name: str, message_type: MessageType = MessageType.TEXT, created_time: int)` - Message domain entity with business logic
57
- - `validate_message_content() -> None` - Validates message content is not empty and under 10MB limit
58
- - `is_from_user() -> bool` - Checks if message is from a user
59
- - `is_from_agent() -> bool` - Checks if message is from an agent
60
- - `is_system_message() -> bool` - Checks if message is a system message
61
- - `id: MessageId` - Unique message identifier
62
- - `session_id: SessionId` - Associated session identifier
63
- - `message: str` - Message content
64
- - `sender_type: SenderType` - Type of sender (USER, AGENT, SYSTEM)
65
- - `sender_name: str` - Name of the message sender
66
- - `message_type: MessageType` - Type of message content
67
- - `created_time: int` - Message creation timestamp
68
-
69
- **Usage Examples:**
70
- ```python
71
- from solace_agent_mesh.gateway.http_sse.repository.entities import Message
72
- from solace_agent_mesh.gateway.http_sse.shared.enums import SenderType, MessageType
73
-
74
- # Create a user message
75
- message = Message(
76
- id="msg_123",
77
- session_id="session_456",
78
- message="Hello, how can I help?",
79
- sender_type=SenderType.USER,
80
- sender_name="John Doe",
81
- message_type=MessageType.TEXT,
82
- created_time=1640995200000
83
- )
84
-
85
- # Validate message content
86
- message.validate_message_content()
87
-
88
- # Check sender type
89
- if message.is_from_user():
90
- print("Message from user")
91
- ```
92
-
93
96
  ### session.py
94
97
  **Purpose:** Defines the Session domain entity with business logic for chat sessions
95
98
  **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Session`
96
99
 
97
100
  **Classes:**
98
- - `Session(id: SessionId, user_id: UserId, name: str | None = None, agent_id: AgentId | None = None, created_time: int, updated_time: int | None = None)` - Session domain entity with business logic
101
+ - `Session(id: SessionId, user_id: UserId, created_time: int, name: str | None = None, agent_id: AgentId | None = None, updated_time: int | None = None)` - Session domain entity with business logic
99
102
  - `update_name(new_name: str) -> None` - Updates session name with validation and sets updated_time
100
103
  - `mark_activity() -> None` - Marks session as having recent activity by updating timestamp
101
104
  - `can_be_deleted_by_user(user_id: UserId) -> bool` - Checks if user can delete this session
@@ -131,51 +134,6 @@ if session.can_be_accessed_by_user("user_456"):
131
134
  print("User can access this session")
132
135
  ```
133
136
 
134
- ### session_history.py
135
- **Purpose:** Defines a composite entity that combines a session with its message history
136
- **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import SessionHistory`
137
-
138
- **Classes:**
139
- - `SessionHistory(session: Session, messages: list[Message] = [], total_message_count: int = 0)` - Composite entity representing a session with its messages
140
- - `session: Session` - The session entity
141
- - `messages: list[Message]` - List of messages in the session
142
- - `total_message_count: int` - Total count of messages (may exceed messages list length for pagination)
143
-
144
- **Usage Examples:**
145
- ```python
146
- from solace_agent_mesh.gateway.http_sse.repository.entities import SessionHistory, Session, Message
147
- from solace_agent_mesh.gateway.http_sse.shared.enums import SenderType
148
-
149
- # Create session history
150
- session = Session(
151
- id="session_123",
152
- user_id="user_456",
153
- created_time=1640995200000
154
- )
155
-
156
- messages = [
157
- Message(
158
- id="msg_1",
159
- session_id="session_123",
160
- message="Hello",
161
- sender_type=SenderType.USER,
162
- sender_name="John",
163
- created_time=1640995200000
164
- )
165
- ]
166
-
167
- history = SessionHistory(
168
- session=session,
169
- messages=messages,
170
- total_message_count=1
171
- )
172
-
173
- # Access session and messages
174
- print(f"Session: {history.session.id}")
175
- print(f"Message count: {len(history.messages)}")
176
- print(f"Total messages: {history.total_message_count}")
177
- ```
178
-
179
137
  ### task.py
180
138
  **Purpose:** Defines the Task domain entity for tracking user tasks with token usage metrics
181
139
  **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import Task`
@@ -225,7 +183,7 @@ task_with_tokens = Task(
225
183
  **Import:** `from solace_agent_mesh.gateway.http_sse.repository.entities import TaskEvent`
226
184
 
227
185
  **Classes:**
228
- - `TaskEvent(id: str, task_id: str, user_id: str | None = None, created_time: int, topic: str, direction: str, payload: dict[str, Any])` - TaskEvent domain entity
186
+ - `TaskEvent(id: str, task_id: str, created_time: int, topic: str, direction: str, payload: dict[str, Any], user_id: str | None = None)` - TaskEvent domain entity
229
187
  - `id: str` - Unique event identifier
230
188
  - `task_id: str` - Associated task identifier
231
189
  - `user_id: str | None` - Optional user identifier
@@ -260,4 +218,4 @@ system_event = TaskEvent(
260
218
  )
261
219
  ```
262
220
 
263
- # content_hash: 14f978bcbf2c820db1c7f3185ffa1529a656b3b5fa0f64cff81927eb2f7d12e9
221
+ # content_hash: d7b07fd8577e43715a286030d4119267ddff5483180284a16dc6d8aab19fd089
@@ -0,0 +1,81 @@
1
+ """
2
+ Project domain entity.
3
+ """
4
+
5
+ from typing import Optional
6
+ from pydantic import BaseModel, Field
7
+
8
+ from ...shared import now_epoch_ms
9
+
10
+
11
+ class Project(BaseModel):
12
+ """Project domain entity with business logic."""
13
+
14
+ id: str
15
+ name: str = Field(..., min_length=1, max_length=255)
16
+ user_id: str
17
+ description: Optional[str] = Field(None, max_length=1000)
18
+ system_prompt: Optional[str] = Field(None, max_length=4000)
19
+ default_agent_id: Optional[str] = None
20
+ created_at: int
21
+ updated_at: Optional[int] = None
22
+ deleted_at: Optional[int] = None
23
+ deleted_by: Optional[str] = None
24
+
25
+ def update_name(self, new_name: str) -> None:
26
+ """Update project name with validation."""
27
+ if not new_name or len(new_name.strip()) == 0:
28
+ raise ValueError("Project name cannot be empty")
29
+ if len(new_name) > 255:
30
+ raise ValueError("Project name cannot exceed 255 characters")
31
+
32
+ self.name = new_name.strip()
33
+ self.updated_at = now_epoch_ms()
34
+
35
+ def update_description(self, new_description: Optional[str]) -> None:
36
+ """Update project description with validation."""
37
+ if new_description is not None:
38
+ if len(new_description) > 1000:
39
+ raise ValueError("Project description cannot exceed 1000 characters")
40
+ self.description = new_description.strip() if new_description else None
41
+ else:
42
+ self.description = None
43
+
44
+ self.updated_at = now_epoch_ms()
45
+
46
+ def update_default_agent(self, agent_id: Optional[str]) -> None:
47
+ """Update project default agent."""
48
+ self.default_agent_id = agent_id
49
+ self.updated_at = now_epoch_ms()
50
+
51
+ def soft_delete(self, user_id: str) -> None:
52
+ """Soft delete the project."""
53
+ if not self.can_be_deleted_by_user(user_id):
54
+ raise ValueError("User does not have permission to delete this project")
55
+
56
+ self.deleted_at = now_epoch_ms()
57
+ self.deleted_by = user_id
58
+ self.updated_at = now_epoch_ms()
59
+
60
+ def is_deleted(self) -> bool:
61
+ """Check if project is soft deleted."""
62
+ return self.deleted_at is not None
63
+
64
+ def can_be_accessed_by_user(self, user_id: str) -> bool:
65
+ """Check if project can be accessed by the given user."""
66
+ # User projects are only accessible by their owner and not deleted
67
+ return self.user_id == user_id and not self.is_deleted()
68
+
69
+ def can_be_edited_by_user(self, user_id: str) -> bool:
70
+ """Check if project can be edited by the given user."""
71
+ # Users can only edit their own projects that are not deleted
72
+ return self.user_id == user_id and not self.is_deleted()
73
+
74
+ def can_be_deleted_by_user(self, user_id: str) -> bool:
75
+ """Check if project can be deleted by the given user."""
76
+ # Users can only delete their own projects that are not already deleted
77
+ return self.user_id == user_id and not self.is_deleted()
78
+
79
+ def mark_as_updated(self) -> None:
80
+ """Mark project as updated."""
81
+ self.updated_at = now_epoch_ms()
@@ -0,0 +1,47 @@
1
+ """
2
+ Project user access domain entity.
3
+ """
4
+
5
+ from typing import Optional
6
+ from pydantic import BaseModel, Field
7
+
8
+ from ...shared import now_epoch_ms
9
+
10
+
11
+ class ProjectUser(BaseModel):
12
+ """
13
+ Project user access domain entity.
14
+
15
+ Represents a user's access to a project with a specific role.
16
+ """
17
+
18
+ id: str
19
+ project_id: str
20
+ user_id: str
21
+ role: str = Field(..., pattern="^(owner|editor|viewer)$")
22
+ added_at: int
23
+ added_by_user_id: str
24
+
25
+ def can_edit_project(self) -> bool:
26
+ """Check if this user can edit the project based on their role."""
27
+ return self.role in ["owner", "editor"]
28
+
29
+ def can_manage_users(self) -> bool:
30
+ """Check if this user can manage other users' access to the project."""
31
+ return self.role == "owner"
32
+
33
+ def can_view_project(self) -> bool:
34
+ """Check if this user can view the project."""
35
+ return self.role in ["owner", "editor", "viewer"]
36
+
37
+ def update_role(self, new_role: str) -> None:
38
+ """Update the user's role with validation."""
39
+ valid_roles = ["owner", "editor", "viewer"]
40
+ if new_role not in valid_roles:
41
+ raise ValueError(f"Invalid role. Must be one of: {', '.join(valid_roles)}")
42
+
43
+ self.role = new_role
44
+
45
+ class Config:
46
+ """Pydantic configuration."""
47
+ frozen = False
@@ -17,8 +17,12 @@ class Session(BaseModel):
17
17
  user_id: UserId
18
18
  name: str | None = None
19
19
  agent_id: AgentId | None = None
20
+ project_id: str | None = None
21
+ project_name: str | None = None
20
22
  created_time: int
21
23
  updated_time: int | None = None
24
+ deleted_at: int | None = None
25
+ deleted_by: str | None = None
22
26
 
23
27
  def update_name(self, new_name: str) -> None:
24
28
  """Update session name with validation."""
@@ -34,10 +38,28 @@ class Session(BaseModel):
34
38
  """Mark session as having recent activity."""
35
39
  self.updated_time = now_epoch_ms()
36
40
 
41
+ def soft_delete(self, user_id: UserId) -> None:
42
+ """Soft delete the session."""
43
+ if not self.can_be_deleted_by_user(user_id):
44
+ raise ValueError("User does not have permission to delete this session")
45
+
46
+ self.deleted_at = now_epoch_ms()
47
+ self.deleted_by = user_id
48
+ self.updated_time = now_epoch_ms()
49
+
50
+ def is_deleted(self) -> bool:
51
+ """Check if session is soft deleted."""
52
+ return self.deleted_at is not None
53
+
54
+ def move_to_project(self, new_project_id: str | None) -> None:
55
+ """Move session to a different project."""
56
+ self.project_id = new_project_id
57
+ self.updated_time = now_epoch_ms()
58
+
37
59
  def can_be_deleted_by_user(self, user_id: UserId) -> bool:
38
60
  """Check if user can delete this session."""
39
61
  return self.user_id == user_id
40
62
 
41
63
  def can_be_accessed_by_user(self, user_id: UserId) -> bool:
42
64
  """Check if user can access this session."""
43
- return self.user_id == user_id
65
+ return self.user_id == user_id and not self.is_deleted()
@@ -4,6 +4,8 @@ Feedback repository implementation using SQLAlchemy.
4
4
 
5
5
  from sqlalchemy.orm import Session as DBSession
6
6
 
7
+ from ..shared.pagination import PaginationParams
8
+ from ..shared.types import UserId
7
9
  from .entities import Feedback
8
10
  from .interfaces import IFeedbackRepository
9
11
  from .models import FeedbackModel
@@ -28,6 +30,51 @@ class FeedbackRepository(IFeedbackRepository):
28
30
  session.refresh(model)
29
31
  return self._model_to_entity(model)
30
32
 
33
+ def search(
34
+ self,
35
+ session: DBSession,
36
+ user_id: UserId,
37
+ start_date: int | None = None,
38
+ end_date: int | None = None,
39
+ task_id: str | None = None,
40
+ session_id: str | None = None,
41
+ rating: str | None = None,
42
+ pagination: PaginationParams | None = None,
43
+ ) -> list[Feedback]:
44
+ """
45
+ Search feedback with flexible filtering.
46
+ All filters are optional and can be combined.
47
+ """
48
+ query = session.query(FeedbackModel)
49
+
50
+ # User filter (unless admin querying all users)
51
+ if user_id != "*":
52
+ query = query.filter(FeedbackModel.user_id == user_id)
53
+
54
+ # Time-based filters
55
+ if start_date:
56
+ query = query.filter(FeedbackModel.created_time >= start_date)
57
+ if end_date:
58
+ query = query.filter(FeedbackModel.created_time <= end_date)
59
+
60
+ # Resource-based filters
61
+ if task_id:
62
+ query = query.filter(FeedbackModel.task_id == task_id)
63
+ if session_id:
64
+ query = query.filter(FeedbackModel.session_id == session_id)
65
+ if rating:
66
+ query = query.filter(FeedbackModel.rating == rating)
67
+
68
+ # Order by most recent first
69
+ query = query.order_by(FeedbackModel.created_time.desc())
70
+
71
+ # Apply pagination
72
+ if pagination:
73
+ query = query.offset(pagination.offset).limit(pagination.page_size)
74
+
75
+ models = query.all()
76
+ return [self._model_to_entity(model) for model in models]
77
+
31
78
  def delete_feedback_older_than(self, session: DBSession, cutoff_time_ms: int, batch_size: int) -> int:
32
79
  """
33
80
  Delete feedback records older than the cutoff time.