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
@@ -1,4 +1,5 @@
1
1
  import logging
2
+ from typing import Optional
2
3
  from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
3
4
  from sqlalchemy.orm import Session
4
5
 
@@ -10,6 +11,8 @@ from ..shared.response_utils import create_data_response
10
11
  from .dto.requests.session_requests import (
11
12
  GetSessionRequest,
12
13
  UpdateSessionRequest,
14
+ MoveSessionRequest,
15
+ SearchSessionsRequest,
13
16
  )
14
17
  from .dto.requests.task_requests import SaveTaskRequest
15
18
  from .dto.responses.session_responses import SessionResponse
@@ -24,6 +27,7 @@ SESSION_NOT_FOUND_MSG = "Session not found."
24
27
 
25
28
  @router.get("/sessions", response_model=PaginatedResponse[SessionResponse])
26
29
  async def get_all_sessions(
30
+ project_id: Optional[str] = Query(default=None, alias="project_id"),
27
31
  page_number: int = Query(default=1, ge=1, alias="pageNumber"),
28
32
  page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
29
33
  db: Session = Depends(get_db),
@@ -31,10 +35,14 @@ async def get_all_sessions(
31
35
  session_service: SessionService = Depends(get_session_business_service),
32
36
  ):
33
37
  user_id = user.get("id")
38
+ log_msg = f"User '{user_id}' is listing sessions with pagination (page={page_number}, size={page_size})"
39
+ if project_id:
40
+ log_msg += f" filtered by project_id={project_id}"
41
+ log.info(log_msg)
34
42
 
35
43
  try:
36
44
  pagination = PaginationParams(page_number=page_number, page_size=page_size)
37
- paginated_response = session_service.get_user_sessions(db, user_id, pagination)
45
+ paginated_response = session_service.get_user_sessions(db, user_id, pagination, project_id=project_id)
38
46
 
39
47
  session_responses = []
40
48
  for session_domain in paginated_response.data:
@@ -43,6 +51,8 @@ async def get_all_sessions(
43
51
  user_id=session_domain.user_id,
44
52
  name=session_domain.name,
45
53
  agent_id=session_domain.agent_id,
54
+ project_id=session_domain.project_id,
55
+ project_name=session_domain.project_name,
46
56
  created_time=session_domain.created_time,
47
57
  updated_time=session_domain.updated_time,
48
58
  )
@@ -58,6 +68,63 @@ async def get_all_sessions(
58
68
  ) from e
59
69
 
60
70
 
71
+ @router.get("/sessions/search", response_model=PaginatedResponse[SessionResponse])
72
+ async def search_sessions(
73
+ query: str = Query(..., min_length=1, description="Search query"),
74
+ project_id: Optional[str] = Query(default=None, alias="projectId"),
75
+ page_number: int = Query(default=1, ge=1, alias="pageNumber"),
76
+ page_size: int = Query(default=20, ge=1, le=100, alias="pageSize"),
77
+ db: Session = Depends(get_db),
78
+ user: dict = Depends(get_current_user),
79
+ session_service: SessionService = Depends(get_session_business_service),
80
+ ):
81
+ """
82
+ Search sessions by name or content.
83
+ """
84
+ user_id = user.get("id")
85
+ log.info(
86
+ "User %s searching sessions with query '%s' (page=%d, size=%d)",
87
+ user_id,
88
+ query,
89
+ page_number,
90
+ page_size,
91
+ )
92
+
93
+ try:
94
+ pagination = PaginationParams(page_number=page_number, page_size=page_size)
95
+ paginated_response = session_service.search_sessions(
96
+ db, user_id, query, pagination, project_id=project_id
97
+ )
98
+
99
+ session_responses = []
100
+ for session_domain in paginated_response.data:
101
+ session_response = SessionResponse(
102
+ id=session_domain.id,
103
+ user_id=session_domain.user_id,
104
+ name=session_domain.name,
105
+ agent_id=session_domain.agent_id,
106
+ project_id=session_domain.project_id,
107
+ project_name=session_domain.project_name,
108
+ created_time=session_domain.created_time,
109
+ updated_time=session_domain.updated_time,
110
+ )
111
+ session_responses.append(session_response)
112
+
113
+ return PaginatedResponse(data=session_responses, meta=paginated_response.meta)
114
+
115
+ except ValueError as e:
116
+ log.warning("Validation error searching sessions: %s", e)
117
+ raise HTTPException(
118
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
119
+ ) from e
120
+ except Exception as e:
121
+ log.error("Error searching sessions for user %s: %s", user_id, e)
122
+ raise HTTPException(
123
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
124
+ detail="Failed to search sessions",
125
+ ) from e
126
+
127
+
61
128
  @router.get("/sessions/{session_id}", response_model=DataResponse[SessionResponse])
62
129
  async def get_session(
63
130
  session_id: str,
@@ -95,6 +162,7 @@ async def get_session(
95
162
  user_id=session_domain.user_id,
96
163
  name=session_domain.name,
97
164
  agent_id=session_domain.agent_id,
165
+ project_id=session_domain.project_id,
98
166
  created_time=session_domain.created_time,
99
167
  updated_time=session_domain.updated_time,
100
168
  )
@@ -399,6 +467,7 @@ async def update_session_name(
399
467
  user_id=updated_domain.user_id,
400
468
  name=updated_domain.name,
401
469
  agent_id=updated_domain.agent_id,
470
+ project_id=updated_domain.project_id,
402
471
  created_time=updated_domain.created_time,
403
472
  updated_time=updated_domain.updated_time,
404
473
  )
@@ -430,8 +499,11 @@ async def delete_session(
430
499
  user: dict = Depends(get_current_user),
431
500
  session_service: SessionService = Depends(get_session_business_service),
432
501
  ):
502
+ """
503
+ Soft delete a session (marks as deleted without removing from database).
504
+ """
433
505
  user_id = user.get("id")
434
- log.info("User %s attempting to delete session %s", user_id, session_id)
506
+ log.info("User %s attempting to soft delete session %s", user_id, session_id)
435
507
 
436
508
  try:
437
509
  if (
@@ -452,7 +524,7 @@ async def delete_session(
452
524
  status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
453
525
  )
454
526
 
455
- log.info("Session %s deleted successfully", session_id)
527
+ log.info("Session %s soft deleted successfully", session_id)
456
528
 
457
529
  except HTTPException:
458
530
  raise
@@ -472,3 +544,82 @@ async def delete_session(
472
544
  status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
473
545
  detail="Failed to delete session",
474
546
  ) from e
547
+
548
+
549
+ @router.patch("/sessions/{session_id}/project", response_model=SessionResponse)
550
+ async def move_session_to_project(
551
+ session_id: str,
552
+ request: MoveSessionRequest,
553
+ db: Session = Depends(get_db),
554
+ user: dict = Depends(get_current_user),
555
+ session_service: SessionService = Depends(get_session_business_service),
556
+ ):
557
+ """
558
+ Move a session to a different project or remove from project.
559
+ """
560
+ user_id = user.get("id")
561
+ log.info(
562
+ "User %s attempting to move session %s to project %s",
563
+ user_id,
564
+ session_id,
565
+ request.project_id,
566
+ )
567
+
568
+ try:
569
+ if (
570
+ not session_id
571
+ or session_id.strip() == ""
572
+ or session_id in ["null", "undefined"]
573
+ ):
574
+ raise HTTPException(
575
+ status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
576
+ )
577
+
578
+ updated_session = session_service.move_session_to_project(
579
+ db=db,
580
+ session_id=session_id,
581
+ user_id=user_id,
582
+ new_project_id=request.project_id,
583
+ )
584
+
585
+ if not updated_session:
586
+ raise HTTPException(
587
+ status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
588
+ )
589
+
590
+ log.info(
591
+ "Session %s moved to project %s successfully",
592
+ session_id,
593
+ request.project_id or "None",
594
+ )
595
+
596
+ return SessionResponse(
597
+ id=updated_session.id,
598
+ user_id=updated_session.user_id,
599
+ name=updated_session.name,
600
+ agent_id=updated_session.agent_id,
601
+ project_id=updated_session.project_id,
602
+ created_time=updated_session.created_time,
603
+ updated_time=updated_session.updated_time,
604
+ )
605
+
606
+ except HTTPException:
607
+ raise
608
+ except ValueError as e:
609
+ log.warning("Validation error moving session %s: %s", session_id, e)
610
+ raise HTTPException(
611
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
612
+ ) from e
613
+ except Exception as e:
614
+ log.error(
615
+ "Error moving session %s for user %s: %s",
616
+ session_id,
617
+ user_id,
618
+ e,
619
+ )
620
+ raise HTTPException(
621
+ status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
622
+ detail="Failed to move session",
623
+ ) from e
624
+
625
+
@@ -3,7 +3,7 @@ API Router for submitting and managing tasks to agents.
3
3
  """
4
4
 
5
5
  import logging
6
- from datetime import datetime
6
+ from datetime import datetime, timezone
7
7
  from typing import TYPE_CHECKING
8
8
 
9
9
  import yaml
@@ -18,9 +18,18 @@ from fastapi import APIRouter, Depends, HTTPException, Response, status
18
18
  from fastapi import Request as FastAPIRequest
19
19
  from sqlalchemy.orm import Session as DBSession
20
20
 
21
+ from ....gateway.http_sse.services.project_service import ProjectService
22
+
23
+ from ....agent.utils.artifact_helpers import (
24
+ get_artifact_info_list,
25
+ load_artifact_content_or_metadata,
26
+ save_artifact_with_metadata,
27
+ )
28
+
21
29
  from ....common import a2a
22
30
  from ....gateway.http_sse.dependencies import (
23
31
  get_db,
32
+ get_project_service_optional,
24
33
  get_sac_component,
25
34
  get_session_business_service,
26
35
  get_session_manager,
@@ -46,20 +55,231 @@ router = APIRouter()
46
55
  log = logging.getLogger(__name__)
47
56
 
48
57
 
58
+ async def _inject_project_context(
59
+ project_id: str,
60
+ message_text: str,
61
+ user_id: str,
62
+ session_id: str,
63
+ project_service: ProjectService,
64
+ component: "WebUIBackendComponent",
65
+ log_prefix: str,
66
+ inject_full_context: bool = True,
67
+ ) -> str:
68
+ """
69
+ Helper function to inject project context and copy artifacts to session.
70
+
71
+ Args:
72
+ inject_full_context: If True, injects full project context (name, description, instructions).
73
+ If False, only copies new artifacts without modifying message text.
74
+ This allows existing sessions to get new project files without
75
+ re-injecting the full context on every message.
76
+
77
+ Returns the modified message text with project context injected (if inject_full_context=True).
78
+ """
79
+ if not project_id or not message_text:
80
+ return message_text
81
+
82
+ from ....gateway.http_sse.dependencies import SessionLocal
83
+
84
+ if SessionLocal is None:
85
+ log.warning("%sProject context injection skipped: database not configured", log_prefix)
86
+ return message_text
87
+
88
+ db = SessionLocal()
89
+ try:
90
+ project = project_service.get_project(db, project_id, user_id)
91
+ if not project:
92
+ return message_text
93
+
94
+ context_parts = []
95
+
96
+ # Only inject full context for new sessions
97
+ if inject_full_context:
98
+ # Start with clear workspace framing
99
+ context_parts.append(f'You are working in the project workspace: "{project.name}"')
100
+
101
+ # Add system prompt if exists
102
+ if project.system_prompt and project.system_prompt.strip():
103
+ context_parts.append(f"\n{project.system_prompt.strip()}")
104
+
105
+ # Add project description if exists
106
+ if project.description and project.description.strip():
107
+ context_parts.append(f"\nProject Description: {project.description.strip()}")
108
+
109
+ # Always copy project artifacts to session (for both new and existing sessions)
110
+ # This ensures new project files are available to existing sessions
111
+ artifact_service = component.get_shared_artifact_service()
112
+ if artifact_service:
113
+ try:
114
+ source_user_id = project.user_id
115
+ project_artifacts_session_id = f"project-{project.id}"
116
+
117
+ log.info("%sChecking for artifacts in project %s (storage session: %s)", log_prefix, project.id, project_artifacts_session_id)
118
+
119
+ project_artifacts = await get_artifact_info_list(
120
+ artifact_service=artifact_service,
121
+ app_name=project_service.app_name,
122
+ user_id=source_user_id,
123
+ session_id=project_artifacts_session_id,
124
+ )
125
+
126
+ if project_artifacts:
127
+ log.info("%sFound %d artifacts in project %s to process.", log_prefix, len(project_artifacts), project.id)
128
+
129
+ # Get list of artifacts already in session to avoid re-copying
130
+ try:
131
+ session_artifacts = await get_artifact_info_list(
132
+ artifact_service=artifact_service,
133
+ app_name=project_service.app_name,
134
+ user_id=user_id,
135
+ session_id=session_id,
136
+ )
137
+ session_artifact_names = {art.filename for art in session_artifacts}
138
+ log.debug("%sSession %s currently has %d artifacts", log_prefix, session_id, len(session_artifact_names))
139
+ except Exception as e:
140
+ log.warning("%sFailed to get session artifacts, will copy all project artifacts: %s", log_prefix, e)
141
+ session_artifact_names = set()
142
+
143
+ all_artifact_descriptions = [] # For new sessions - all files
144
+ new_artifact_descriptions = [] # For existing sessions - only new files
145
+ artifacts_copied = 0
146
+
147
+ for artifact_info in project_artifacts:
148
+ # Build description for all artifacts (for new sessions)
149
+ desc_str = f"- {artifact_info.filename}"
150
+ if artifact_info.description:
151
+ desc_str += f": {artifact_info.description}"
152
+ all_artifact_descriptions.append(desc_str)
153
+
154
+ # Skip if artifact already exists in session (any source)
155
+ if artifact_info.filename in session_artifact_names:
156
+ log.debug("%sSkipping artifact %s - already exists in session", log_prefix, artifact_info.filename)
157
+ continue
158
+
159
+ # Track new artifacts for existing sessions
160
+ new_artifact_descriptions.append(desc_str)
161
+
162
+ log.info("%sCopying new artifact %s to session %s", log_prefix, artifact_info.filename, session_id)
163
+
164
+ try:
165
+ # Load artifact content from project storage
166
+ loaded_artifact = await load_artifact_content_or_metadata(
167
+ artifact_service=artifact_service,
168
+ app_name=project_service.app_name,
169
+ user_id=source_user_id,
170
+ session_id=project_artifacts_session_id,
171
+ filename=artifact_info.filename,
172
+ return_raw_bytes=True,
173
+ version="latest"
174
+ )
175
+
176
+ # Load the full metadata separately
177
+ loaded_metadata = await load_artifact_content_or_metadata(
178
+ artifact_service=artifact_service,
179
+ app_name=project_service.app_name,
180
+ user_id=source_user_id,
181
+ session_id=project_artifacts_session_id,
182
+ filename=artifact_info.filename,
183
+ load_metadata_only=True,
184
+ version="latest"
185
+ )
186
+
187
+ # Save a copy to the current chat session
188
+ if loaded_artifact.get("status") == "success":
189
+ full_metadata = loaded_metadata.get("metadata", {}) if loaded_metadata.get("status") == "success" else {}
190
+
191
+ # Ensure the source is always set for copied project artifacts
192
+ full_metadata["source"] = "project"
193
+
194
+ await save_artifact_with_metadata(
195
+ artifact_service=artifact_service,
196
+ app_name=project_service.app_name,
197
+ user_id=user_id,
198
+ session_id=session_id,
199
+ filename=artifact_info.filename,
200
+ content_bytes=loaded_artifact.get("raw_bytes"),
201
+ mime_type=loaded_artifact.get("mime_type"),
202
+ metadata_dict=full_metadata,
203
+ timestamp=datetime.now(timezone.utc),
204
+ )
205
+ artifacts_copied += 1
206
+ log.info("%sSuccessfully copied artifact %s to session", log_prefix, artifact_info.filename)
207
+ else:
208
+ log.warning("%sFailed to load artifact %s: %s", log_prefix, artifact_info.filename, loaded_artifact.get("status"))
209
+ except Exception as e:
210
+ log.error("%sError copying artifact %s to session: %s", log_prefix, artifact_info.filename, e)
211
+ # Continue with other artifacts even if one fails
212
+
213
+ # Add artifact descriptions to context
214
+ if inject_full_context and all_artifact_descriptions:
215
+ # New session: show all project files
216
+ artifacts_context = (
217
+ "\nFiles in Session:\n"
218
+ "The following files are available in your session and can be viewed using your tools if required:\n"
219
+ + "\n".join(all_artifact_descriptions)
220
+ )
221
+ context_parts.append(artifacts_context)
222
+ elif not inject_full_context and new_artifact_descriptions:
223
+ # Existing session: notify about newly added files
224
+ new_files_context = (
225
+ "\nNew Files Added to Project:\n"
226
+ "The following files have been added to the project and are now available in your session:\n"
227
+ + "\n".join(new_artifact_descriptions)
228
+ )
229
+ context_parts.append(new_files_context)
230
+
231
+ if artifacts_copied > 0:
232
+ log.info("%sCopied %d new artifacts to session %s.", log_prefix, artifacts_copied, session_id)
233
+ else:
234
+ log.debug("%sNo new artifacts to copy to session %s.", log_prefix, session_id)
235
+ else:
236
+ log.info("%sNo artifacts found in project %s to copy.", log_prefix, project.id)
237
+
238
+ except Exception as e:
239
+ log.warning("%sFailed to copy project artifacts to session: %s", log_prefix, e)
240
+ # Do not fail the entire request, just log the warning
241
+
242
+ # Inject all gathered context into the message, ending with user query
243
+ # Only modify message text if we're injecting full context (new sessions)
244
+ modified_message_text = message_text
245
+ if context_parts:
246
+ project_context = "\n".join(context_parts)
247
+ modified_message_text = f"{project_context}\n\nUSER QUERY:\n{message_text}"
248
+ log.info("%sInjected full project context for project: %s", log_prefix, project_id)
249
+ else:
250
+ log.debug("%sSkipped full context injection for existing session, but ensured new artifacts are copied", log_prefix)
251
+
252
+ return modified_message_text
253
+
254
+ except Exception as e:
255
+ log.warning("%sFailed to inject project context: %s", log_prefix, e)
256
+ # Continue without injection - don't fail the request
257
+ return message_text
258
+ finally:
259
+ db.close()
260
+
261
+
49
262
  async def _submit_task(
50
263
  request: FastAPIRequest,
51
264
  payload: SendMessageRequest | SendStreamingMessageRequest,
52
265
  session_manager: SessionManager,
53
266
  component: "WebUIBackendComponent",
267
+ project_service: ProjectService | None,
54
268
  is_streaming: bool,
55
269
  session_service: SessionService | None = None,
56
270
  ):
57
- """Helper to submit a task, handling both streaming and non-streaming cases."""
271
+ """
272
+ Helper to submit a task, handling both streaming and non-streaming cases.
273
+
274
+ Also handles project context injection.
275
+ """
58
276
  log_prefix = f"[POST /api/v1/message:{'stream' if is_streaming else 'send'}] "
59
277
 
60
278
  agent_name = None
279
+ project_id = None
61
280
  if payload.params and payload.params.message and payload.params.message.metadata:
62
281
  agent_name = payload.params.message.metadata.get("agent_name")
282
+ project_id = payload.params.message.metadata.get("project_id")
63
283
 
64
284
  if not agent_name:
65
285
  raise HTTPException(
@@ -99,6 +319,21 @@ async def _submit_task(
99
319
  user_id = user_identity.get("id")
100
320
  from ....gateway.http_sse.dependencies import SessionLocal
101
321
 
322
+ # If project_id not in metadata, check if session has a project_id in database
323
+ # This handles cases where sessions are moved to projects after creation
324
+ if not project_id and session_service and frontend_session_id:
325
+ if SessionLocal is not None:
326
+ db = SessionLocal()
327
+ try:
328
+ session_details = session_service.get_session_details(db, frontend_session_id, user_id)
329
+ if session_details and session_details.project_id:
330
+ project_id = session_details.project_id
331
+ log.info("%sFound project_id %s from session database for session %s", log_prefix, project_id, frontend_session_id)
332
+ except Exception as e:
333
+ log.warning("%sFailed to lookup session project_id: %s", log_prefix, e)
334
+ finally:
335
+ db.close()
336
+
102
337
  if frontend_session_id:
103
338
  session_id = frontend_session_id
104
339
  log.info(
@@ -123,6 +358,7 @@ async def _submit_task(
123
358
  user_id=user_id,
124
359
  agent_id=agent_name,
125
360
  session_id=session_id,
361
+ project_id=project_id,
126
362
  )
127
363
  db.commit()
128
364
  log.debug(
@@ -140,8 +376,60 @@ async def _submit_task(
140
376
  "%sUsing ClientID: %s, SessionID: %s", log_prefix, client_id, session_id
141
377
  )
142
378
 
143
- # Use the helper to get the unwrapped parts from the incoming message.
144
- a2a_parts = a2a.get_parts_from_message(payload.params.message)
379
+ # Extract message text and apply project context injection
380
+ message_text = ""
381
+ if payload.params and payload.params.message:
382
+ parts = a2a.get_parts_from_message(payload.params.message)
383
+ for part in parts:
384
+ if hasattr(part, "text"):
385
+ message_text = part.text
386
+ break
387
+
388
+ # Project context injection - always inject for project sessions to ensure new files are available
389
+ # Skip if project_service is None (persistence disabled)
390
+ modified_message = payload.params.message
391
+ if project_service and project_id and message_text:
392
+ # Inject context for new sessions (includes full context + artifact copy)
393
+ # For existing sessions, only copy new artifacts without re-injecting full context
394
+ should_inject_full_context = not frontend_session_id
395
+
396
+ modified_message_text = await _inject_project_context(
397
+ project_id=project_id,
398
+ message_text=message_text,
399
+ user_id=user_id,
400
+ session_id=session_id,
401
+ project_service=project_service,
402
+ component=component,
403
+ log_prefix=log_prefix,
404
+ inject_full_context=should_inject_full_context,
405
+ )
406
+
407
+ # Update the message with project context if it was modified
408
+ if modified_message_text != message_text:
409
+ # Create new text part with project context
410
+ new_text_part = a2a.create_text_part(modified_message_text)
411
+
412
+ # Get existing parts and replace the first text part with the modified one
413
+ existing_parts = a2a.get_parts_from_message(payload.params.message)
414
+ new_parts = []
415
+ text_part_replaced = False
416
+
417
+ for part in existing_parts:
418
+ if hasattr(part, "text") and not text_part_replaced:
419
+ new_parts.append(new_text_part)
420
+ text_part_replaced = True
421
+ else:
422
+ new_parts.append(part)
423
+
424
+ # If no text part was found, add the new text part at the beginning
425
+ if not text_part_replaced:
426
+ new_parts.insert(0, new_text_part)
427
+
428
+ # Update the message with the new parts
429
+ modified_message = a2a.update_message_parts(payload.params.message, new_parts)
430
+
431
+ # Use the helper to get the unwrapped parts from the modified message (with project context if applied).
432
+ a2a_parts = a2a.get_parts_from_message(modified_message)
145
433
 
146
434
  external_req_ctx = {
147
435
  "app_name_for_artifacts": component.gateway_id,
@@ -341,6 +629,7 @@ async def send_task_to_agent(
341
629
  payload: SendMessageRequest,
342
630
  session_manager: SessionManager = Depends(get_session_manager),
343
631
  component: "WebUIBackendComponent" = Depends(get_sac_component),
632
+ project_service: ProjectService | None = Depends(get_project_service_optional),
344
633
  ):
345
634
  """
346
635
  Submits a non-streaming task request to the specified agent.
@@ -351,6 +640,7 @@ async def send_task_to_agent(
351
640
  payload=payload,
352
641
  session_manager=session_manager,
353
642
  component=component,
643
+ project_service=project_service,
354
644
  is_streaming=False,
355
645
  session_service=None,
356
646
  )
@@ -362,6 +652,7 @@ async def subscribe_task_from_agent(
362
652
  payload: SendStreamingMessageRequest,
363
653
  session_manager: SessionManager = Depends(get_session_manager),
364
654
  component: "WebUIBackendComponent" = Depends(get_sac_component),
655
+ project_service: ProjectService | None = Depends(get_project_service_optional),
365
656
  session_service: SessionService = Depends(get_session_business_service),
366
657
  ):
367
658
  """
@@ -374,6 +665,7 @@ async def subscribe_task_from_agent(
374
665
  payload=payload,
375
666
  session_manager=session_manager,
376
667
  component=component,
668
+ project_service=project_service,
377
669
  is_streaming=True,
378
670
  session_service=session_service,
379
671
  )