solace-agent-mesh 1.6.3__py3-none-any.whl → 1.7.1__py3-none-any.whl

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

Potentially problematic release.


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

Files changed (244) 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/stream_parser.py +6 -1
  9. solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
  10. solace_agent_mesh/agent/agent_llm.txt +61 -70
  11. solace_agent_mesh/agent/protocol/event_handlers.py +29 -1
  12. solace_agent_mesh/agent/protocol/protocol_llm.txt +1 -1
  13. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +190 -0
  14. solace_agent_mesh/agent/proxies/base/base_llm.txt +148 -0
  15. solace_agent_mesh/agent/proxies/proxies_llm.txt +283 -0
  16. solace_agent_mesh/agent/sac/app.py +22 -0
  17. solace_agent_mesh/agent/sac/component.py +76 -40
  18. solace_agent_mesh/agent/sac/sac_llm.txt +1 -1
  19. solace_agent_mesh/agent/sac/task_execution_context.py +21 -0
  20. solace_agent_mesh/agent/testing/testing_llm.txt +2 -1
  21. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +13 -148
  22. solace_agent_mesh/agent/tools/dynamic_tool.py +2 -0
  23. solace_agent_mesh/agent/tools/tools_llm.txt +93 -80
  24. solace_agent_mesh/agent/tools/tools_llm_detail.txt +3 -2
  25. solace_agent_mesh/agent/utils/artifact_helpers.py +4 -0
  26. solace_agent_mesh/agent/utils/utils_llm.txt +16 -2
  27. solace_agent_mesh/assets/docs/404.html +3 -3
  28. solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +1 -0
  29. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +1 -0
  30. solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +1 -0
  31. solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
  32. solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +1 -0
  34. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +1 -0
  35. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +1 -0
  36. solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
  37. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +1 -0
  38. solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
  39. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
  40. solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
  41. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +1 -0
  42. solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
  43. solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/{ab9708a8.3e6dd091.js → ab9708a8.245ae0ef.js} +1 -1
  45. solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
  46. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +1 -0
  47. solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/{e6f9706b.e74a984d.js → e6f9706b.045d0fa1.js} +1 -1
  55. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +1 -0
  56. solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/main.f213fe0c.js +2 -0
  59. solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +1 -0
  60. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
  62. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
  63. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
  64. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +18 -4
  65. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +4 -4
  66. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +4 -4
  67. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +5 -5
  68. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +4 -4
  69. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
  70. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
  71. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +196 -0
  72. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +4 -4
  73. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +5 -5
  74. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +6 -7
  75. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
  76. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +47 -0
  77. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +4 -4
  78. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +4 -4
  79. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
  80. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +160 -169
  81. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +4 -4
  82. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
  83. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +4 -4
  84. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +4 -4
  85. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
  86. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
  87. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +5 -5
  88. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +4 -4
  89. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +4 -4
  90. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
  91. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
  92. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
  93. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
  94. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
  95. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +59 -0
  96. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +62 -0
  97. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +10 -6
  98. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +4 -4
  99. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +4 -4
  100. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
  101. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +27 -4
  102. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
  103. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +4 -4
  104. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +5 -4
  105. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +3 -3
  106. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +3 -3
  107. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +290 -0
  108. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +9 -9
  109. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +4 -4
  110. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +4 -4
  111. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +4 -4
  112. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +4 -4
  113. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
  114. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
  115. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +3 -3
  116. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +3 -3
  117. solace_agent_mesh/assets/docs/lunr-index-1762283454666.json +1 -0
  118. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  119. solace_agent_mesh/assets/docs/search-doc-1762283454666.json +1 -0
  120. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  121. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  122. solace_agent_mesh/cli/__init__.py +1 -1
  123. solace_agent_mesh/cli/commands/docs_cmd.py +4 -1
  124. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +1 -1
  125. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-D4_RMYRh.js → authCallback-tcIFZLis.js} +1 -1
  126. solace_agent_mesh/client/webui/frontend/static/assets/{client-UZ3qU6Bq.js → client-CRYdKo2Q.js} +3 -3
  127. solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +1 -0
  128. solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +353 -0
  129. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CINwxvwV.js +470 -0
  130. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  131. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  132. solace_agent_mesh/common/a2a/a2a_llm.txt +13 -20
  133. solace_agent_mesh/common/a2a/protocol.py +5 -0
  134. solace_agent_mesh/common/a2a/types.py +1 -0
  135. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +49 -11
  136. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
  137. solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
  138. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +26 -9
  139. solace_agent_mesh/common/common_llm.txt +13 -34
  140. solace_agent_mesh/common/data_parts.py +20 -4
  141. solace_agent_mesh/common/middleware/middleware_llm.txt +1 -1
  142. solace_agent_mesh/common/sac/sac_llm.txt +1 -1
  143. solace_agent_mesh/common/sam_events/sam_events_llm.txt +1 -1
  144. solace_agent_mesh/common/services/employee_service.py +1 -1
  145. solace_agent_mesh/common/services/providers/providers_llm.txt +3 -2
  146. solace_agent_mesh/common/services/services_llm.txt +9 -4
  147. solace_agent_mesh/common/utils/embeds/constants.py +1 -0
  148. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +1 -1
  149. solace_agent_mesh/common/utils/embeds/modifiers.py +2 -1
  150. solace_agent_mesh/common/utils/embeds/resolver.py +58 -6
  151. solace_agent_mesh/common/utils/embeds/types.py +8 -0
  152. solace_agent_mesh/common/utils/utils_llm.txt +5 -6
  153. solace_agent_mesh/core_a2a/core_a2a_llm.txt +1 -1
  154. solace_agent_mesh/gateway/adapter/__init__.py +1 -0
  155. solace_agent_mesh/gateway/adapter/base.py +143 -0
  156. solace_agent_mesh/gateway/adapter/types.py +221 -0
  157. solace_agent_mesh/gateway/base/app.py +29 -2
  158. solace_agent_mesh/gateway/base/base_llm.txt +10 -8
  159. solace_agent_mesh/gateway/base/component.py +573 -142
  160. solace_agent_mesh/gateway/gateway_llm.txt +55 -59
  161. solace_agent_mesh/gateway/generic/__init__.py +1 -0
  162. solace_agent_mesh/gateway/generic/app.py +50 -0
  163. solace_agent_mesh/gateway/generic/component.py +650 -0
  164. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +99 -49
  165. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +92 -0
  166. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
  167. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +150 -0
  168. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
  169. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
  170. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +26 -20
  171. solace_agent_mesh/gateway/http_sse/app.py +0 -14
  172. solace_agent_mesh/gateway/http_sse/component.py +17 -56
  173. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +1 -1
  174. solace_agent_mesh/gateway/http_sse/dependencies.py +21 -3
  175. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +8 -8
  176. solace_agent_mesh/gateway/http_sse/main.py +23 -5
  177. solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
  178. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +56 -98
  179. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
  180. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
  181. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +23 -1
  182. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
  183. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +112 -4
  184. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +9 -1
  185. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +51 -60
  186. solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
  187. solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
  188. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +7 -1
  189. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
  190. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
  191. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +125 -157
  192. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +269 -8
  193. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +143 -51
  194. solace_agent_mesh/gateway/http_sse/routers/config.py +69 -0
  195. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +198 -94
  196. solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
  197. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +68 -18
  198. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +13 -0
  199. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +30 -0
  200. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +51 -35
  201. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +2 -0
  202. solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
  203. solace_agent_mesh/gateway/http_sse/routers/projects.py +542 -0
  204. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +9 -11
  205. solace_agent_mesh/gateway/http_sse/routers/sessions.py +154 -3
  206. solace_agent_mesh/gateway/http_sse/routers/tasks.py +296 -4
  207. solace_agent_mesh/gateway/http_sse/services/project_service.py +403 -0
  208. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +16 -10
  209. solace_agent_mesh/gateway/http_sse/services/session_service.py +178 -6
  210. solace_agent_mesh/gateway/http_sse/shared/exception_handlers.py +2 -3
  211. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +48 -14
  212. solace_agent_mesh/solace_agent_mesh_llm.txt +1 -1
  213. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/METADATA +3 -5
  214. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/RECORD +218 -175
  215. solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
  216. solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +0 -1
  217. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
  218. solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
  219. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
  220. solace_agent_mesh/assets/docs/assets/js/631738c7.7c4594c9.js +0 -1
  221. solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
  222. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
  223. solace_agent_mesh/assets/docs/assets/js/71da7b71.ddbdfbe2.js +0 -1
  224. solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +0 -1
  225. solace_agent_mesh/assets/docs/assets/js/94e8668d.3b883666.js +0 -1
  226. solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
  227. solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
  228. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
  229. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
  230. solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
  231. solace_agent_mesh/assets/docs/assets/js/e92d0134.4f395c6b.js +0 -1
  232. solace_agent_mesh/assets/docs/assets/js/f284c35a.720d2ef2.js +0 -1
  233. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
  234. solace_agent_mesh/assets/docs/assets/js/main.ed05b14d.js +0 -2
  235. solace_agent_mesh/assets/docs/assets/js/runtime~main.a8a75e0b.js +0 -1
  236. solace_agent_mesh/assets/docs/lunr-index-1761744323675.json +0 -1
  237. solace_agent_mesh/assets/docs/search-doc-1761744323675.json +0 -1
  238. solace_agent_mesh/client/webui/frontend/static/assets/main--3yJYl7S.css +0 -1
  239. solace_agent_mesh/client/webui/frontend/static/assets/main-DojKHS49.js +0 -342
  240. solace_agent_mesh/client/webui/frontend/static/assets/vendor-DSqhjwq_.js +0 -405
  241. /solace_agent_mesh/assets/docs/assets/js/{main.ed05b14d.js.LICENSE.txt → main.f213fe0c.js.LICENSE.txt} +0 -0
  242. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/WHEEL +0 -0
  243. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/entry_points.txt +0 -0
  244. {solace_agent_mesh-1.6.3.dist-info → solace_agent_mesh-1.7.1.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,542 @@
1
+ """
2
+ Project API controller using 3-tiered architecture.
3
+ """
4
+
5
+ import json
6
+ from typing import List, Optional, Dict, Any
7
+ from fastapi import (
8
+ APIRouter,
9
+ Depends,
10
+ HTTPException,
11
+ status,
12
+ Request,
13
+ Form,
14
+ File,
15
+ UploadFile,
16
+ )
17
+ from sqlalchemy.orm import Session
18
+ from solace_ai_connector.common.log import log
19
+
20
+ from ..dependencies import get_project_service, get_sac_component, get_api_config, get_db
21
+ from ..services.project_service import ProjectService
22
+ from ..shared.auth_utils import get_current_user
23
+ from ....common.a2a.types import ArtifactInfo
24
+ from typing import TYPE_CHECKING
25
+
26
+ if TYPE_CHECKING:
27
+ from ..component import WebUIBackendComponent
28
+
29
+ from .dto.requests.project_requests import (
30
+ CreateProjectRequest,
31
+ UpdateProjectRequest,
32
+ GetProjectRequest,
33
+ GetProjectsRequest,
34
+ DeleteProjectRequest,
35
+ )
36
+ from .dto.responses.project_responses import (
37
+ ProjectResponse,
38
+ ProjectListResponse,
39
+ )
40
+
41
+ router = APIRouter()
42
+
43
+
44
+ def check_projects_enabled(
45
+ component: "WebUIBackendComponent" = Depends(get_sac_component),
46
+ api_config: Dict[str, Any] = Depends(get_api_config),
47
+ ) -> None:
48
+ """
49
+ Dependency to check if projects feature is enabled.
50
+ Raises HTTPException if projects are disabled.
51
+ """
52
+ # Check if persistence is enabled (required for projects)
53
+ persistence_enabled = api_config.get("persistence_enabled", False)
54
+ if not persistence_enabled:
55
+ log.warning("Projects API called but persistence is not enabled")
56
+ raise HTTPException(
57
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
58
+ detail="Projects feature requires persistence to be enabled. Please configure session_service.type as 'sql'."
59
+ )
60
+
61
+ # Check explicit projects config
62
+ projects_config = component.get_config("projects", {})
63
+ if isinstance(projects_config, dict):
64
+ projects_explicitly_enabled = projects_config.get("enabled", True)
65
+ if not projects_explicitly_enabled:
66
+ log.warning("Projects API called but projects are explicitly disabled in config")
67
+ raise HTTPException(
68
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
69
+ detail="Projects feature is disabled. Please enable it in the configuration."
70
+ )
71
+
72
+ # Check frontend_feature_enablement override
73
+ feature_flags = component.get_config("frontend_feature_enablement", {})
74
+ if "projects" in feature_flags:
75
+ projects_flag = feature_flags.get("projects", True)
76
+ if not projects_flag:
77
+ log.warning("Projects API called but projects are disabled via feature flag")
78
+ raise HTTPException(
79
+ status_code=status.HTTP_501_NOT_IMPLEMENTED,
80
+ detail="Projects feature is disabled via feature flag."
81
+ )
82
+
83
+
84
+ @router.post("/projects", response_model=ProjectResponse, status_code=status.HTTP_201_CREATED)
85
+ async def create_project(
86
+ name: str = Form(...),
87
+ description: Optional[str] = Form(None),
88
+ system_prompt: Optional[str] = Form(None, alias="systemPrompt"),
89
+ default_agent_id: Optional[str] = Form(None, alias="defaultAgentId"),
90
+ file_metadata: Optional[str] = Form(None, alias="fileMetadata"),
91
+ files: Optional[List[UploadFile]] = File(None),
92
+ user: dict = Depends(get_current_user),
93
+ project_service: ProjectService = Depends(get_project_service),
94
+ db: Session = Depends(get_db),
95
+ _: None = Depends(check_projects_enabled),
96
+ ):
97
+ """
98
+ Create a new project for the authenticated user.
99
+ """
100
+ user_id = user.get("id")
101
+ log.info(f"Creating project '{name}' for user {user_id}")
102
+ log.info(f"Received system_prompt: {system_prompt}")
103
+ log.info(f"Received file_metadata: {file_metadata}")
104
+
105
+ try:
106
+ if files:
107
+ log.info(f"Received {len(files)} files for project creation:")
108
+ for file in files:
109
+ log.info(f" - Filename: {file.filename}, Content-Type: {file.content_type}")
110
+ else:
111
+ log.info("No files received for project creation.")
112
+
113
+ request_dto = CreateProjectRequest(
114
+ name=name,
115
+ description=description,
116
+ system_prompt=system_prompt,
117
+ default_agent_id=default_agent_id,
118
+ file_metadata=file_metadata,
119
+ user_id=user_id
120
+ )
121
+
122
+ parsed_file_metadata = {}
123
+ if request_dto.file_metadata:
124
+ try:
125
+ parsed_file_metadata = json.loads(request_dto.file_metadata)
126
+ except json.JSONDecodeError:
127
+ log.warning("Could not parse file_metadata JSON string, ignoring.")
128
+ pass
129
+
130
+ project = await project_service.create_project(
131
+ db=db,
132
+ name=request_dto.name,
133
+ user_id=request_dto.user_id,
134
+ description=request_dto.description,
135
+ system_prompt=request_dto.system_prompt,
136
+ default_agent_id=request_dto.default_agent_id,
137
+ files=files,
138
+ file_metadata=parsed_file_metadata,
139
+ )
140
+
141
+ return ProjectResponse(
142
+ id=project.id,
143
+ name=project.name,
144
+ user_id=project.user_id,
145
+ description=project.description,
146
+ system_prompt=project.system_prompt,
147
+ default_agent_id=project.default_agent_id,
148
+ created_at=project.created_at,
149
+ updated_at=project.updated_at,
150
+ )
151
+
152
+ except ValueError as e:
153
+ log.warning(f"Validation error creating project: {e}")
154
+ raise HTTPException(
155
+ status_code=status.HTTP_400_BAD_REQUEST,
156
+ detail=str(e)
157
+ )
158
+ except Exception as e:
159
+ log.error("Error creating project for user %s: %s", user_id, e)
160
+ raise HTTPException(
161
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
162
+ detail="Failed to create project"
163
+ )
164
+
165
+
166
+ @router.get("/projects", response_model=ProjectListResponse)
167
+ async def get_user_projects(
168
+ user: dict = Depends(get_current_user),
169
+ project_service: ProjectService = Depends(get_project_service),
170
+ db: Session = Depends(get_db),
171
+ _: None = Depends(check_projects_enabled),
172
+ ):
173
+ """
174
+ Get all projects owned by the authenticated user.
175
+ """
176
+ user_id = user.get("id")
177
+ log.info(f"Fetching projects for user_id: {user_id}")
178
+
179
+ try:
180
+ request_dto = GetProjectsRequest(user_id=user_id)
181
+
182
+ projects = project_service.get_user_projects(db, request_dto.user_id)
183
+
184
+ project_responses = [
185
+ ProjectResponse(
186
+ id=p.id,
187
+ name=p.name,
188
+ user_id=p.user_id,
189
+ description=p.description,
190
+ system_prompt=p.system_prompt,
191
+ default_agent_id=p.default_agent_id,
192
+ created_at=p.created_at,
193
+ updated_at=p.updated_at,
194
+ )
195
+ for p in projects
196
+ ]
197
+
198
+ return ProjectListResponse(
199
+ projects=project_responses,
200
+ total=len(project_responses)
201
+ )
202
+
203
+ except Exception as e:
204
+ log.error("Error fetching projects for user %s: %s", user_id, e)
205
+ raise HTTPException(
206
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
207
+ detail="Failed to retrieve projects"
208
+ )
209
+
210
+
211
+ @router.get("/projects/{project_id}", response_model=ProjectResponse)
212
+ async def get_project(
213
+ project_id: str,
214
+ user: dict = Depends(get_current_user),
215
+ project_service: ProjectService = Depends(get_project_service),
216
+ db: Session = Depends(get_db),
217
+ _: None = Depends(check_projects_enabled),
218
+ ):
219
+ """
220
+ Get a specific project by ID.
221
+ """
222
+ user_id = user.get("id")
223
+ log.info("User %s attempting to fetch project_id: %s", user_id, project_id)
224
+
225
+ try:
226
+ if (
227
+ not project_id
228
+ or project_id.strip() == ""
229
+ or project_id in ["null", "undefined"]
230
+ ):
231
+ raise HTTPException(
232
+ status_code=status.HTTP_404_NOT_FOUND, detail="Project not found."
233
+ )
234
+
235
+ request_dto = GetProjectRequest(project_id=project_id, user_id=user_id)
236
+
237
+ project = project_service.get_project(
238
+ db=db,
239
+ project_id=request_dto.project_id,
240
+ user_id=request_dto.user_id
241
+ )
242
+
243
+ if not project:
244
+ raise HTTPException(
245
+ status_code=status.HTTP_404_NOT_FOUND,
246
+ detail="Project not found."
247
+ )
248
+
249
+ log.info("User %s authorized. Fetching project_id: %s", user_id, project_id)
250
+
251
+ return ProjectResponse(
252
+ id=project.id,
253
+ name=project.name,
254
+ user_id=project.user_id,
255
+ description=project.description,
256
+ system_prompt=project.system_prompt,
257
+ default_agent_id=project.default_agent_id,
258
+ created_at=project.created_at,
259
+ updated_at=project.updated_at,
260
+ )
261
+
262
+ except HTTPException:
263
+ raise
264
+ except Exception as e:
265
+ log.error(
266
+ "Error fetching project %s for user %s: %s",
267
+ project_id,
268
+ user_id,
269
+ e,
270
+ )
271
+ raise HTTPException(
272
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
273
+ detail="Failed to retrieve project"
274
+ )
275
+
276
+
277
+ @router.get("/projects/{project_id}/artifacts", response_model=List[ArtifactInfo])
278
+ async def get_project_artifacts(
279
+ project_id: str,
280
+ user: dict = Depends(get_current_user),
281
+ project_service: ProjectService = Depends(get_project_service),
282
+ db: Session = Depends(get_db),
283
+ _: None = Depends(check_projects_enabled),
284
+ ):
285
+ """
286
+ Get all artifacts for a specific project.
287
+ """
288
+ user_id = user.get("id")
289
+ log.info("User %s attempting to fetch artifacts for project_id: %s", user_id, project_id)
290
+
291
+ try:
292
+ artifacts = await project_service.get_project_artifacts(
293
+ db=db, project_id=project_id, user_id=user_id
294
+ )
295
+ return artifacts
296
+ except ValueError as e:
297
+ log.warning(f"Validation error getting project artifacts: {e}")
298
+ raise HTTPException(
299
+ status_code=status.HTTP_404_NOT_FOUND,
300
+ detail=str(e)
301
+ )
302
+ except Exception as e:
303
+ log.error(
304
+ "Error fetching artifacts for project %s for user %s: %s",
305
+ project_id,
306
+ user_id,
307
+ e,
308
+ )
309
+ raise HTTPException(
310
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
311
+ detail="Failed to retrieve project artifacts"
312
+ )
313
+
314
+
315
+ @router.post("/projects/{project_id}/artifacts", status_code=status.HTTP_201_CREATED)
316
+ async def add_project_artifacts(
317
+ project_id: str,
318
+ files: List[UploadFile] = File(...),
319
+ file_metadata: Optional[str] = Form(None, alias="fileMetadata"),
320
+ user: dict = Depends(get_current_user),
321
+ project_service: ProjectService = Depends(get_project_service),
322
+ db: Session = Depends(get_db),
323
+ _: None = Depends(check_projects_enabled),
324
+ ):
325
+ """
326
+ Add one or more artifacts to a project.
327
+ """
328
+ user_id = user.get("id")
329
+ log.info(f"User {user_id} attempting to add artifacts to project {project_id}")
330
+
331
+ try:
332
+ parsed_file_metadata = {}
333
+ if file_metadata:
334
+ try:
335
+ parsed_file_metadata = json.loads(file_metadata)
336
+ except json.JSONDecodeError:
337
+ log.warning(f"Could not parse file_metadata for project {project_id}, ignoring.")
338
+ pass
339
+
340
+ results = await project_service.add_artifacts_to_project(
341
+ db=db,
342
+ project_id=project_id,
343
+ user_id=user_id,
344
+ files=files,
345
+ file_metadata=parsed_file_metadata
346
+ )
347
+ return results
348
+ except ValueError as e:
349
+ log.warning(f"Validation error adding artifacts to project {project_id}: {e}")
350
+ # Could be 404 if project not found, or 400 if other validation fails
351
+ if "not found" in str(e).lower():
352
+ raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail=str(e))
353
+ raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
354
+ except Exception as e:
355
+ log.error(
356
+ "Error adding artifacts to project %s for user %s: %s",
357
+ project_id,
358
+ user_id,
359
+ e,
360
+ )
361
+ raise HTTPException(
362
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
363
+ detail="Failed to add artifacts to project"
364
+ )
365
+
366
+
367
+ @router.delete("/projects/{project_id}/artifacts/{filename}", status_code=status.HTTP_204_NO_CONTENT)
368
+ async def delete_project_artifact(
369
+ project_id: str,
370
+ filename: str,
371
+ user: dict = Depends(get_current_user),
372
+ project_service: ProjectService = Depends(get_project_service),
373
+ db: Session = Depends(get_db),
374
+ _: None = Depends(check_projects_enabled),
375
+ ):
376
+ """
377
+ Delete an artifact from a project.
378
+ """
379
+ user_id = user.get("id")
380
+ log.info(f"User {user_id} attempting to delete artifact '{filename}' from project {project_id}")
381
+
382
+ try:
383
+ success = await project_service.delete_artifact_from_project(
384
+ db=db,
385
+ project_id=project_id,
386
+ user_id=user_id,
387
+ filename=filename,
388
+ )
389
+ if not success:
390
+ raise HTTPException(
391
+ status_code=status.HTTP_404_NOT_FOUND,
392
+ detail="Project not found or access denied."
393
+ )
394
+
395
+ return
396
+ except ValueError as e:
397
+ log.warning(f"Validation error deleting artifact from project {project_id}: {e}")
398
+ raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(e))
399
+ except HTTPException:
400
+ raise
401
+ except Exception as e:
402
+ log.error(
403
+ "Error deleting artifact '%s' from project %s for user %s: %s",
404
+ filename,
405
+ project_id,
406
+ user_id,
407
+ e,
408
+ )
409
+ raise HTTPException(
410
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
411
+ detail="Failed to delete artifact from project"
412
+ )
413
+
414
+
415
+ @router.put("/projects/{project_id}", response_model=ProjectResponse)
416
+ async def update_project(
417
+ project_id: str,
418
+ request: UpdateProjectRequest,
419
+ user: dict = Depends(get_current_user),
420
+ project_service: ProjectService = Depends(get_project_service),
421
+ db: Session = Depends(get_db),
422
+ _: None = Depends(check_projects_enabled),
423
+ ):
424
+ """
425
+ Update a project's details.
426
+ """
427
+ user_id = user.get("id")
428
+ log.info("User %s attempting to update project %s", user_id, project_id)
429
+
430
+ try:
431
+ if (
432
+ not project_id
433
+ or project_id.strip() == ""
434
+ or project_id in ["null", "undefined"]
435
+ ):
436
+ raise HTTPException(
437
+ status_code=status.HTTP_404_NOT_FOUND, detail="Project not found."
438
+ )
439
+
440
+ update_fields = request.model_dump(exclude_unset=True, by_alias=False)
441
+
442
+ # Pass only explicitly set fields to the service
443
+ kwargs = {
444
+ 'db': db,
445
+ 'project_id': project_id,
446
+ 'user_id': user_id,
447
+ 'name': update_fields.get('name', ...),
448
+ 'description': update_fields.get('description', ...),
449
+ 'system_prompt': update_fields.get('system_prompt', ...),
450
+ 'default_agent_id': update_fields.get('default_agent_id', ...),
451
+ }
452
+
453
+ project = project_service.update_project(**kwargs)
454
+
455
+ if not project:
456
+ raise HTTPException(
457
+ status_code=status.HTTP_404_NOT_FOUND,
458
+ detail="Project not found."
459
+ )
460
+
461
+ log.info("Project %s updated successfully", project_id)
462
+
463
+ return ProjectResponse(
464
+ id=project.id,
465
+ name=project.name,
466
+ user_id=project.user_id,
467
+ description=project.description,
468
+ system_prompt=project.system_prompt,
469
+ default_agent_id=project.default_agent_id,
470
+ created_at=project.created_at,
471
+ updated_at=project.updated_at,
472
+ )
473
+
474
+ except HTTPException:
475
+ raise
476
+ except ValueError as e:
477
+ log.warning("Validation error updating project %s: %s", project_id, e)
478
+ raise HTTPException(
479
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
480
+ )
481
+ except Exception as e:
482
+ log.error(
483
+ "Error updating project %s for user %s: %s",
484
+ project_id,
485
+ user_id,
486
+ e,
487
+ )
488
+ raise HTTPException(
489
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
490
+ detail="Failed to update project"
491
+ )
492
+
493
+
494
+ @router.delete("/projects/{project_id}", status_code=status.HTTP_204_NO_CONTENT)
495
+ async def delete_project(
496
+ project_id: str,
497
+ user: dict = Depends(get_current_user),
498
+ project_service: ProjectService = Depends(get_project_service),
499
+ db: Session = Depends(get_db),
500
+ _: None = Depends(check_projects_enabled),
501
+ ):
502
+ """
503
+ Soft delete a project (marks as deleted without removing from database).
504
+ """
505
+ user_id = user.get("id")
506
+ log.info("User %s attempting to soft delete project %s", user_id, project_id)
507
+
508
+ try:
509
+ request_dto = DeleteProjectRequest(project_id=project_id, user_id=user_id)
510
+
511
+ success = project_service.soft_delete_project(
512
+ db=db,
513
+ project_id=request_dto.project_id,
514
+ user_id=request_dto.user_id
515
+ )
516
+
517
+ if not success:
518
+ raise HTTPException(
519
+ status_code=status.HTTP_404_NOT_FOUND,
520
+ detail="Project not found."
521
+ )
522
+
523
+ log.info("Project %s soft deleted successfully", project_id)
524
+
525
+ except HTTPException:
526
+ raise
527
+ except ValueError as e:
528
+ log.warning("Validation error deleting project %s: %s", project_id, e)
529
+ raise HTTPException(
530
+ status_code=status.HTTP_400_BAD_REQUEST, detail=str(e)
531
+ )
532
+ except Exception as e:
533
+ log.error(
534
+ "Error deleting project %s for user %s: %s",
535
+ project_id,
536
+ user_id,
537
+ e,
538
+ )
539
+ raise HTTPException(
540
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
541
+ detail="Failed to delete project"
542
+ )
@@ -49,7 +49,6 @@ The `routers` directory contains FastAPI router modules that define the REST API
49
49
  - `get_latest_artifact(session_id: str, filename: str) -> StreamingResponse` - Downloads latest artifact version with embed resolution
50
50
  - `get_specific_artifact_version(session_id: str, filename: str, version: Union[int, str]) -> StreamingResponse` - Downloads specific version
51
51
  - `get_artifact_by_uri(uri: str) -> StreamingResponse` - Downloads artifact by formal artifact:// URI
52
- - `upload_artifact(session_id: str, filename: str, upload_file: UploadFile, metadata_json: Optional[str]) -> Dict[str, Any]` - Uploads new artifact version with metadata
53
52
  - `delete_artifact(session_id: str, filename: str) -> Response` - Deletes artifact and all versions
54
53
 
55
54
  #### auth.py
@@ -100,6 +99,8 @@ The `routers` directory contains FastAPI router modules that define the REST API
100
99
  - `get_session_history(session_id: str, user: dict) -> List[MessageResponse]` - Gets session message history
101
100
  - `update_session_name(session_id: str, name: str, user: dict) -> SessionResponse` - Updates session name with validation
102
101
  - `delete_session(session_id: str, user: dict) -> None` - Deletes session with cascade notifications
102
+ - `save_task(session_id: str, request: SaveTaskRequest, user: dict) -> TaskResponse` - Saves complete task interaction (upsert)
103
+ - `get_session_tasks(session_id: str, user: dict) -> TaskListResponse` - Gets all tasks for a session
103
104
 
104
105
  #### sse.py
105
106
  **Purpose:** Provides Server-Sent Events endpoint for real-time streaming
@@ -293,22 +294,19 @@ import httpx
293
294
  import json
294
295
  from pathlib import Path
295
296
 
296
- # Upload an artifact with metadata using session-based endpoint
297
+ # Upload an artifact with metadata and automatic session creation
297
298
  async def upload_artifact_with_metadata(session_id: str, filename: str, file_path: Path, metadata: dict = None):
298
299
  files = {"upload_file": (filename, file_path.open("rb"))}
299
- data = {}
300
+ data = {
301
+ "sessionId": session_id, # Can be null/empty to create new session
302
+ "filename": filename
303
+ }
300
304
 
301
305
  if metadata:
302
306
  data["metadata_json"] = json.dumps(metadata)
303
307
 
304
308
  async with httpx.AsyncClient() as client:
305
309
  response = await client.post(
306
- f"http://localhost:8000/api/v1/artifacts/{session_id}/{filename}",
307
- files=files,
308
- data=data
309
- )
310
- return response.json()
311
-
312
- # Upload artifact with automatic session creation
310
+ "http://localhost:
313
311
 
314
- # content_hash: a98ae1eb7e5483f6e9438569a4c3dd2df4d9992a968e84230d41cf18d2d34624
312
+ # content_hash: 8e5e35d1d55cb448656d32d58b4600db192110e8de163a93765eef3e04086329