solace-agent-mesh 1.7.1__py3-none-any.whl → 1.13.2__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 (447) hide show
  1. solace_agent_mesh/agent/adk/alembic/README +74 -0
  2. solace_agent_mesh/agent/adk/alembic/env.py +77 -0
  3. solace_agent_mesh/agent/adk/alembic/script.py.mako +28 -0
  4. solace_agent_mesh/agent/adk/alembic/versions/e2902798564d_adk_session_db_upgrade.py +52 -0
  5. solace_agent_mesh/agent/adk/alembic.ini +112 -0
  6. solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +164 -0
  7. solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
  8. solace_agent_mesh/agent/adk/callbacks.py +752 -127
  9. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +99 -7
  10. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +52 -5
  11. solace_agent_mesh/agent/adk/mcp_content_processor.py +1 -1
  12. solace_agent_mesh/agent/adk/models/lite_llm.py +34 -16
  13. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
  14. solace_agent_mesh/agent/adk/runner.py +66 -8
  15. solace_agent_mesh/agent/adk/schema_migration.py +88 -0
  16. solace_agent_mesh/agent/adk/services.py +41 -1
  17. solace_agent_mesh/agent/adk/setup.py +220 -32
  18. solace_agent_mesh/agent/adk/stream_parser.py +229 -40
  19. solace_agent_mesh/agent/protocol/event_handlers.py +219 -33
  20. solace_agent_mesh/agent/proxies/a2a/component.py +572 -75
  21. solace_agent_mesh/agent/proxies/a2a/config.py +80 -4
  22. solace_agent_mesh/agent/proxies/base/component.py +188 -22
  23. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +3 -1
  24. solace_agent_mesh/agent/sac/app.py +37 -12
  25. solace_agent_mesh/agent/sac/component.py +322 -52
  26. solace_agent_mesh/agent/sac/patch_adk.py +8 -16
  27. solace_agent_mesh/agent/sac/task_execution_context.py +90 -0
  28. solace_agent_mesh/agent/tools/__init__.py +3 -0
  29. solace_agent_mesh/agent/tools/audio_tools.py +3 -3
  30. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +698 -24
  31. solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
  32. solace_agent_mesh/agent/tools/peer_agent_tool.py +82 -15
  33. solace_agent_mesh/agent/tools/time_tools.py +126 -0
  34. solace_agent_mesh/agent/tools/tool_config_types.py +54 -2
  35. solace_agent_mesh/agent/tools/web_search_tools.py +279 -0
  36. solace_agent_mesh/agent/tools/web_tools.py +125 -17
  37. solace_agent_mesh/agent/utils/artifact_helpers.py +243 -5
  38. solace_agent_mesh/agent/utils/context_helpers.py +17 -0
  39. solace_agent_mesh/assets/docs/404.html +6 -6
  40. solace_agent_mesh/assets/docs/assets/css/{styles.906a1503.css → styles.8162edfb.css} +1 -1
  41. solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
  42. solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
  43. solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
  44. solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
  45. solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
  46. solace_agent_mesh/assets/docs/assets/js/{17896441.a5e82f9b.js.LICENSE.txt → 2279.550aa580.js.LICENSE.txt} +6 -0
  47. solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/3ac1795d.7f7ab1c1.js +1 -0
  51. solace_agent_mesh/assets/docs/assets/js/3ff0015d.e53c9b78.js +1 -0
  52. solace_agent_mesh/assets/docs/assets/js/41adc471.0e95b87c.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/49eed117.493d6f99.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/{509e993c.4c7a1a6d.js → 509e993c.a1fbf45a.js} +1 -1
  56. solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
  62. solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/81a99df0.7ed65d45.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/f284c35a.cc97854c.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/main.d634009f.js +2 -0
  87. solace_agent_mesh/assets/docs/assets/js/runtime~main.27bb82a7.js +1 -0
  88. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +68 -68
  89. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +50 -50
  90. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +42 -42
  91. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +55 -55
  92. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +75 -75
  93. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
  94. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +67 -50
  95. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/research-tools/index.html +136 -0
  96. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +178 -144
  97. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +43 -42
  98. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +20 -18
  99. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +23 -23
  100. solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
  101. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +45 -45
  102. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +98 -112
  103. solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
  104. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +208 -125
  105. solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
  106. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +28 -28
  107. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -29
  108. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +14 -14
  109. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/index.html +47 -0
  110. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
  111. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +67 -53
  112. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -17
  113. solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
  114. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +38 -38
  115. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +87 -87
  116. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +67 -49
  117. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +17 -17
  118. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +51 -51
  119. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +22 -22
  120. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +27 -27
  121. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +135 -135
  122. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +66 -66
  123. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +51 -51
  124. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +50 -38
  125. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +86 -86
  126. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +51 -51
  127. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +24 -24
  128. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +30 -30
  129. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +44 -44
  130. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
  131. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +50 -23
  132. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +29 -24
  133. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +21 -21
  134. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +40 -37
  135. solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
  136. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +96 -66
  137. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +181 -181
  138. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +75 -75
  139. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +27 -27
  140. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +44 -44
  141. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +39 -38
  142. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +30 -30
  143. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +18 -18
  144. solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
  145. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +135 -114
  146. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +37 -37
  147. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +14 -14
  148. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +27 -25
  149. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +69 -69
  150. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +72 -72
  151. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +112 -112
  152. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +28 -28
  153. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +42 -42
  154. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +20 -20
  155. solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
  156. solace_agent_mesh/assets/docs/lunr-index-1768329217460.json +1 -0
  157. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  158. solace_agent_mesh/assets/docs/search-doc-1768329217460.json +1 -0
  159. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  160. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  161. solace_agent_mesh/cli/__init__.py +1 -1
  162. solace_agent_mesh/cli/commands/add_cmd/__init__.py +3 -1
  163. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -1
  164. solace_agent_mesh/cli/commands/add_cmd/proxy_cmd.py +100 -0
  165. solace_agent_mesh/cli/commands/eval_cmd.py +1 -1
  166. solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
  167. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
  168. solace_agent_mesh/cli/commands/init_cmd/env_step.py +30 -3
  169. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +3 -4
  170. solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
  171. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +16 -3
  172. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +2 -1
  173. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
  174. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +3 -3
  175. solace_agent_mesh/cli/commands/run_cmd.py +64 -49
  176. solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
  177. solace_agent_mesh/cli/main.py +15 -0
  178. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-tcIFZLis.js → authCallback-KnKMP_vb.js} +1 -1
  179. solace_agent_mesh/client/webui/frontend/static/assets/client-DpBL2stg.js +25 -0
  180. solace_agent_mesh/client/webui/frontend/static/assets/main-Cd498TV2.js +435 -0
  181. solace_agent_mesh/client/webui/frontend/static/assets/main-rSf8Vu29.css +1 -0
  182. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-CINwxvwV.js → vendor-CGk8Suyh.js} +189 -94
  183. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  184. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  185. solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
  186. solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
  187. solace_agent_mesh/common/a2a/types.py +1 -1
  188. solace_agent_mesh/common/agent_registry.py +38 -11
  189. solace_agent_mesh/common/data_parts.py +124 -0
  190. solace_agent_mesh/common/error_handlers.py +83 -0
  191. solace_agent_mesh/common/exceptions.py +24 -0
  192. solace_agent_mesh/common/oauth/__init__.py +17 -0
  193. solace_agent_mesh/common/oauth/oauth_client.py +408 -0
  194. solace_agent_mesh/common/oauth/utils.py +50 -0
  195. solace_agent_mesh/common/rag_dto.py +156 -0
  196. solace_agent_mesh/common/sac/sam_component_base.py +73 -1
  197. solace_agent_mesh/common/sam_events/event_service.py +2 -2
  198. solace_agent_mesh/common/utils/embeds/converter.py +1 -8
  199. solace_agent_mesh/common/utils/embeds/modifiers.py +2 -27
  200. solace_agent_mesh/common/utils/embeds/resolver.py +94 -25
  201. solace_agent_mesh/common/utils/embeds/types.py +1 -0
  202. solace_agent_mesh/common/utils/log_formatters.py +20 -0
  203. solace_agent_mesh/common/utils/mime_helpers.py +12 -5
  204. solace_agent_mesh/common/utils/rbac_utils.py +69 -0
  205. solace_agent_mesh/common/utils/templates/__init__.py +8 -0
  206. solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
  207. solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
  208. solace_agent_mesh/config_portal/backend/common.py +12 -0
  209. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-CljP4_mv.js +103 -0
  210. solace_agent_mesh/config_portal/frontend/static/client/assets/{components-Rk0n-9cK.js → components-CaC6hG8d.js} +22 -22
  211. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-mvZjNKiz.js → entry.client-H_TM0YBt.js} +3 -3
  212. solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DzNKzXrc.js → index-CnFykb2v.js} +16 -16
  213. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-f8439d40.js +1 -0
  214. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BIMqslJB.css +1 -0
  215. solace_agent_mesh/config_portal/frontend/static/client/assets/root-mJmTIdIk.js +10 -0
  216. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  217. solace_agent_mesh/core_a2a/service.py +3 -2
  218. solace_agent_mesh/gateway/adapter/base.py +28 -1
  219. solace_agent_mesh/gateway/adapter/types.py +9 -0
  220. solace_agent_mesh/gateway/base/app.py +10 -0
  221. solace_agent_mesh/gateway/base/auth_interface.py +103 -0
  222. solace_agent_mesh/gateway/base/component.py +451 -10
  223. solace_agent_mesh/gateway/generic/component.py +274 -30
  224. solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
  225. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +2 -43
  226. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +2 -2
  227. solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
  228. solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
  229. solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
  230. solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
  231. solace_agent_mesh/gateway/http_sse/alembic.ini +0 -36
  232. solace_agent_mesh/gateway/http_sse/app.py +23 -6
  233. solace_agent_mesh/gateway/http_sse/component.py +158 -73
  234. solace_agent_mesh/gateway/http_sse/dependencies.py +50 -57
  235. solace_agent_mesh/gateway/http_sse/main.py +58 -482
  236. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
  237. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +1 -1
  238. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +1 -1
  239. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +3 -2
  240. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
  241. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +2 -2
  242. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +2 -2
  243. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +5 -0
  244. solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
  245. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +1 -1
  246. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
  247. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +1 -1
  248. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +1 -1
  249. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +12 -107
  250. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +86 -2
  251. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +38 -7
  252. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +113 -7
  253. solace_agent_mesh/gateway/http_sse/routers/auth.py +69 -132
  254. solace_agent_mesh/gateway/http_sse/routers/config.py +235 -10
  255. solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
  256. solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
  257. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +1 -1
  258. solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
  259. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +1 -0
  260. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +3 -2
  261. solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
  262. solace_agent_mesh/gateway/http_sse/routers/feedback.py +2 -2
  263. solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
  264. solace_agent_mesh/gateway/http_sse/routers/projects.py +250 -24
  265. solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
  266. solace_agent_mesh/gateway/http_sse/routers/sessions.py +14 -5
  267. solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
  268. solace_agent_mesh/gateway/http_sse/routers/sse.py +117 -4
  269. solace_agent_mesh/gateway/http_sse/routers/tasks.py +509 -149
  270. solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
  271. solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
  272. solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
  273. solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
  274. solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
  275. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
  276. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
  277. solace_agent_mesh/gateway/http_sse/services/project_service.py +539 -12
  278. solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
  279. solace_agent_mesh/gateway/http_sse/services/session_service.py +198 -21
  280. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
  281. solace_agent_mesh/gateway/http_sse/sse_manager.py +280 -169
  282. solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
  283. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +41 -1
  284. solace_agent_mesh/services/__init__.py +0 -0
  285. solace_agent_mesh/services/platform/__init__.py +29 -0
  286. solace_agent_mesh/services/platform/alembic/env.py +85 -0
  287. solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
  288. solace_agent_mesh/services/platform/alembic.ini +109 -0
  289. solace_agent_mesh/services/platform/api/__init__.py +3 -0
  290. solace_agent_mesh/services/platform/api/dependencies.py +154 -0
  291. solace_agent_mesh/services/platform/api/main.py +314 -0
  292. solace_agent_mesh/services/platform/api/middleware.py +51 -0
  293. solace_agent_mesh/services/platform/api/routers/__init__.py +33 -0
  294. solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
  295. solace_agent_mesh/services/platform/app.py +215 -0
  296. solace_agent_mesh/services/platform/component.py +777 -0
  297. solace_agent_mesh/shared/__init__.py +14 -0
  298. solace_agent_mesh/shared/api/__init__.py +42 -0
  299. solace_agent_mesh/shared/auth/__init__.py +26 -0
  300. solace_agent_mesh/shared/auth/dependencies.py +204 -0
  301. solace_agent_mesh/shared/auth/middleware.py +347 -0
  302. solace_agent_mesh/shared/database/__init__.py +20 -0
  303. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
  304. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
  305. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
  306. solace_agent_mesh/shared/exceptions/__init__.py +36 -0
  307. solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +1 -1
  308. solace_agent_mesh/shared/utils/__init__.py +21 -0
  309. solace_agent_mesh/templates/logging_config_template.yaml +48 -0
  310. solace_agent_mesh/templates/main_orchestrator.yaml +12 -1
  311. solace_agent_mesh/templates/platform.yaml +49 -0
  312. solace_agent_mesh/templates/plugin_readme_template.md +3 -25
  313. solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
  314. solace_agent_mesh/templates/proxy_template.yaml +62 -0
  315. solace_agent_mesh/templates/webui.yaml +148 -6
  316. solace_agent_mesh/tools/web_search/__init__.py +18 -0
  317. solace_agent_mesh/tools/web_search/base.py +84 -0
  318. solace_agent_mesh/tools/web_search/google_search.py +247 -0
  319. solace_agent_mesh/tools/web_search/models.py +99 -0
  320. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +29 -8
  321. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/RECORD +334 -313
  322. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
  323. solace_agent_mesh/agent/adk/adk_llm.txt +0 -226
  324. solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
  325. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
  326. solace_agent_mesh/agent/adk/models/models_llm.txt +0 -189
  327. solace_agent_mesh/agent/agent_llm.txt +0 -369
  328. solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
  329. solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
  330. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
  331. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +0 -190
  332. solace_agent_mesh/agent/proxies/base/base_llm.txt +0 -148
  333. solace_agent_mesh/agent/proxies/proxies_llm.txt +0 -283
  334. solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
  335. solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
  336. solace_agent_mesh/agent/testing/testing_llm.txt +0 -58
  337. solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
  338. solace_agent_mesh/agent/tools/tools_llm.txt +0 -276
  339. solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -275
  340. solace_agent_mesh/agent/utils/utils_llm.txt +0 -152
  341. solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
  342. solace_agent_mesh/assets/docs/assets/js/05749d90.c70b2be9.js +0 -1
  343. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +0 -1
  344. solace_agent_mesh/assets/docs/assets/js/15e40e79.36003774.js +0 -1
  345. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
  346. solace_agent_mesh/assets/docs/assets/js/240a0364.c39f8388.js +0 -1
  347. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
  348. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
  349. solace_agent_mesh/assets/docs/assets/js/3ac1795d.e4870a49.js +0 -1
  350. solace_agent_mesh/assets/docs/assets/js/3ff0015d.b63ee53a.js +0 -1
  351. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +0 -1
  352. solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
  353. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.45b32c2b.js +0 -1
  354. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +0 -1
  355. solace_agent_mesh/assets/docs/assets/js/66d4869e.830d443f.js +0 -1
  356. solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
  357. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +0 -1
  358. solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +0 -1
  359. solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +0 -1
  360. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +0 -1
  361. solace_agent_mesh/assets/docs/assets/js/94e8668d.09ed9234.js +0 -1
  362. solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +0 -1
  363. solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +0 -1
  364. solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +0 -1
  365. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
  366. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.f902fad8.js +0 -1
  367. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +0 -1
  368. solace_agent_mesh/assets/docs/assets/js/e04b235d.c9c50c7b.js +0 -1
  369. solace_agent_mesh/assets/docs/assets/js/e3d9abda.d11c67a7.js +0 -1
  370. solace_agent_mesh/assets/docs/assets/js/e6f9706b.045d0fa1.js +0 -1
  371. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +0 -1
  372. solace_agent_mesh/assets/docs/assets/js/f284c35a.5099c51e.js +0 -1
  373. solace_agent_mesh/assets/docs/assets/js/main.f213fe0c.js +0 -2
  374. solace_agent_mesh/assets/docs/assets/js/runtime~main.d9606d6a.js +0 -1
  375. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes-deployment/index.html +0 -47
  376. solace_agent_mesh/assets/docs/lunr-index-1762283454666.json +0 -1
  377. solace_agent_mesh/assets/docs/search-doc-1762283454666.json +0 -1
  378. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
  379. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
  380. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
  381. solace_agent_mesh/client/webui/frontend/static/assets/client-CRYdKo2Q.js +0 -25
  382. solace_agent_mesh/client/webui/frontend/static/assets/main-CojeY_1w.css +0 -1
  383. solace_agent_mesh/client/webui/frontend/static/assets/main-ILja9MCG.js +0 -353
  384. solace_agent_mesh/common/a2a/a2a_llm.txt +0 -175
  385. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
  386. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -445
  387. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
  388. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -330
  389. solace_agent_mesh/common/common_llm.txt +0 -230
  390. solace_agent_mesh/common/common_llm_detail.txt +0 -2562
  391. solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
  392. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
  393. solace_agent_mesh/common/sac/sac_llm.txt +0 -71
  394. solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
  395. solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
  396. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
  397. solace_agent_mesh/common/services/providers/providers_llm.txt +0 -81
  398. solace_agent_mesh/common/services/services_llm.txt +0 -368
  399. solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
  400. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
  401. solace_agent_mesh/common/utils/utils_llm.txt +0 -335
  402. solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
  403. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +0 -98
  404. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-61038fc6.js +0 -1
  405. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BWvk5-gF.js +0 -10
  406. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +0 -1
  407. solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
  408. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
  409. solace_agent_mesh/gateway/base/base_llm.txt +0 -226
  410. solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
  411. solace_agent_mesh/gateway/gateway_llm.txt +0 -369
  412. solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
  413. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -345
  414. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_fulltext_search_indexes.py +0 -92
  415. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -161
  416. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
  417. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
  418. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
  419. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -221
  420. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -257
  421. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -308
  422. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -450
  423. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -133
  424. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -123
  425. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -312
  426. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -303
  427. solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
  428. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -319
  429. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
  430. solace_agent_mesh/llm.txt +0 -228
  431. solace_agent_mesh/llm_detail.txt +0 -2835
  432. solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
  433. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
  434. solace_agent_mesh/templates/logging_config_template.ini +0 -45
  435. solace_agent_mesh/templates/templates_llm.txt +0 -147
  436. /solace_agent_mesh/assets/docs/assets/js/{main.f213fe0c.js.LICENSE.txt → main.d634009f.js.LICENSE.txt} +0 -0
  437. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
  438. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
  439. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
  440. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
  441. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
  442. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
  443. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
  444. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
  445. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
  446. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
  447. {solace_agent_mesh-1.7.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/licenses/LICENSE +0 -0
@@ -1,13 +1,14 @@
1
1
  import logging
2
2
  from typing import Optional
3
3
  from fastapi import APIRouter, Body, Depends, HTTPException, Query, status
4
+ from pydantic import ValidationError
4
5
  from sqlalchemy.orm import Session
5
6
 
6
7
  from ..dependencies import get_session_business_service, get_db
7
8
  from ..services.session_service import SessionService
8
- from ..shared.auth_utils import get_current_user
9
- from ..shared.pagination import DataResponse, PaginatedResponse, PaginationParams
10
- from ..shared.response_utils import create_data_response
9
+ from solace_agent_mesh.shared.api.auth_utils import get_current_user
10
+ from solace_agent_mesh.shared.api.pagination import DataResponse, PaginatedResponse, PaginationParams
11
+ from solace_agent_mesh.shared.api.response_utils import create_data_response
11
12
  from .dto.requests.session_requests import (
12
13
  GetSessionRequest,
13
14
  UpdateSessionRequest,
@@ -53,6 +54,7 @@ async def get_all_sessions(
53
54
  agent_id=session_domain.agent_id,
54
55
  project_id=session_domain.project_id,
55
56
  project_name=session_domain.project_name,
57
+ has_running_background_task=session_domain.has_running_background_task,
56
58
  created_time=session_domain.created_time,
57
59
  updated_time=session_domain.updated_time,
58
60
  )
@@ -79,7 +81,7 @@ async def search_sessions(
79
81
  session_service: SessionService = Depends(get_session_business_service),
80
82
  ):
81
83
  """
82
- Search sessions by name or content.
84
+ Search sessions by name/title only.
83
85
  """
84
86
  user_id = user.get("id")
85
87
  log.info(
@@ -105,6 +107,7 @@ async def search_sessions(
105
107
  agent_id=session_domain.agent_id,
106
108
  project_id=session_domain.project_id,
107
109
  project_name=session_domain.project_name,
110
+ has_running_background_task=session_domain.has_running_background_task,
108
111
  created_time=session_domain.created_time,
109
112
  updated_time=session_domain.updated_time,
110
113
  )
@@ -474,6 +477,11 @@ async def update_session_name(
474
477
 
475
478
  except HTTPException:
476
479
  raise
480
+ except ValidationError as e:
481
+ log.warning("Pydantic validation error updating session %s: %s", session_id, e)
482
+ raise HTTPException(
483
+ status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=str(e)
484
+ ) from e
477
485
  except ValueError as e:
478
486
  log.warning("Validation error updating session %s: %s", session_id, e)
479
487
  raise HTTPException(
@@ -556,6 +564,7 @@ async def move_session_to_project(
556
564
  ):
557
565
  """
558
566
  Move a session to a different project or remove from project.
567
+ When moving to a project, artifacts from that project are immediately copied to the session.
559
568
  """
560
569
  user_id = user.get("id")
561
570
  log.info(
@@ -575,7 +584,7 @@ async def move_session_to_project(
575
584
  status_code=status.HTTP_404_NOT_FOUND, detail=SESSION_NOT_FOUND_MSG
576
585
  )
577
586
 
578
- updated_session = session_service.move_session_to_project(
587
+ updated_session = await session_service.move_session_to_project(
579
588
  db=db,
580
589
  session_id=session_id,
581
590
  user_id=user_id,
@@ -0,0 +1,355 @@
1
+ """
2
+ Speech API routes for STT and TTS functionality.
3
+ """
4
+
5
+ from typing import Optional
6
+ from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
7
+ from fastapi.responses import StreamingResponse, Response
8
+ from pydantic import BaseModel
9
+
10
+ from solace_ai_connector.common.log import log
11
+
12
+ from ..services.audio_service import AudioService
13
+ from ..dependencies import get_audio_service
14
+ from solace_agent_mesh.shared.api.auth_utils import get_current_user
15
+
16
+
17
+ router = APIRouter()
18
+
19
+
20
+ class TTSRequest(BaseModel):
21
+ """Request model for text-to-speech"""
22
+ input: str
23
+ voice: Optional[str] = None
24
+ messageId: Optional[str] = None
25
+ provider: Optional[str] = None
26
+
27
+
28
+ class StreamTTSRequest(BaseModel):
29
+ """Request model for streaming text-to-speech"""
30
+ input: str
31
+ voice: Optional[str] = None
32
+ runId: Optional[str] = None
33
+ provider: Optional[str] = None
34
+
35
+
36
+ @router.post("/stt")
37
+ async def speech_to_text(
38
+ audio: UploadFile = File(...),
39
+ provider: Optional[str] = Form(None),
40
+ language: Optional[str] = Form(None),
41
+ user: dict = Depends(get_current_user),
42
+ audio_service: AudioService = Depends(get_audio_service)
43
+ ):
44
+ """
45
+ Transcribe audio to text using configured STT service.
46
+
47
+ Args:
48
+ audio: Audio file (wav, mp3, webm, ogg)
49
+ provider: Optional provider override (openai, azure)
50
+ language: Optional language code (e.g., "en-US", "es-ES")
51
+ user: Current authenticated user
52
+ audio_service: Audio service instance
53
+
54
+ Returns:
55
+ JSON with transcribed text:
56
+ {
57
+ "text": "transcribed text",
58
+ "language": "en",
59
+ "duration": 5.2
60
+ }
61
+
62
+ Raises:
63
+ HTTPException: If transcription fails
64
+ """
65
+ log.info(
66
+ "[SpeechAPI] STT request from user=%s, filename=%s, provider=%s, language=%s",
67
+ user.get("user_id"),
68
+ audio.filename,
69
+ provider,
70
+ language
71
+ )
72
+
73
+ try:
74
+ # Validate content type
75
+ if not audio.content_type or not audio.content_type.startswith("audio/"):
76
+ raise HTTPException(
77
+ 415,
78
+ f"Unsupported media type: {audio.content_type}. Expected audio/*"
79
+ )
80
+
81
+ result = await audio_service.transcribe_audio(
82
+ audio_file=audio,
83
+ user_id=user.get("user_id", "anonymous"),
84
+ session_id=user.get("session_id", "default"),
85
+ app_name=user.get("app_name", "webui"),
86
+ provider=provider,
87
+ language=language
88
+ )
89
+
90
+ return result.to_dict()
91
+
92
+ except HTTPException:
93
+ raise
94
+ except Exception as e:
95
+ log.exception("[SpeechAPI] STT error: %s", e)
96
+ raise HTTPException(500, f"Transcription failed: {str(e)}")
97
+
98
+
99
+ @router.post("/tts")
100
+ async def text_to_speech(
101
+ request: TTSRequest,
102
+ user: dict = Depends(get_current_user),
103
+ audio_service: AudioService = Depends(get_audio_service)
104
+ ):
105
+ """
106
+ Convert text to speech using configured TTS service.
107
+
108
+ Args:
109
+ request: TTS request with text and voice
110
+ user: Current authenticated user
111
+ audio_service: Audio service instance
112
+
113
+ Returns:
114
+ Audio data as MP3
115
+
116
+ Raises:
117
+ HTTPException: If generation fails
118
+ """
119
+ log.info(
120
+ "[SpeechAPI] TTS request from user=%s, text_len=%d, voice=%s",
121
+ user.get("user_id"),
122
+ len(request.input),
123
+ request.voice
124
+ )
125
+
126
+ try:
127
+ # Validate input
128
+ if not request.input or not request.input.strip():
129
+ raise HTTPException(400, "Input text is required")
130
+
131
+ if len(request.input) > 10000:
132
+ raise HTTPException(
133
+ 413,
134
+ "Text too long (max 10000 characters). Use /tts/stream for longer text."
135
+ )
136
+
137
+ audio_data = await audio_service.generate_speech(
138
+ text=request.input,
139
+ voice=request.voice,
140
+ user_id=user.get("user_id", "anonymous"),
141
+ session_id=user.get("session_id", "default"),
142
+ app_name=user.get("app_name", "webui"),
143
+ message_id=request.messageId,
144
+ provider=request.provider # NEW: Pass provider from request
145
+ )
146
+
147
+ return Response(
148
+ content=audio_data,
149
+ media_type="audio/mpeg"
150
+ )
151
+
152
+ except HTTPException:
153
+ raise
154
+ except Exception as e:
155
+ log.exception("[SpeechAPI] TTS error: %s", e)
156
+ raise HTTPException(500, f"TTS generation failed: {str(e)}")
157
+
158
+
159
+ @router.post("/tts/stream")
160
+ async def stream_audio(
161
+ request: StreamTTSRequest,
162
+ user: dict = Depends(get_current_user),
163
+ audio_service: AudioService = Depends(get_audio_service)
164
+ ):
165
+ """
166
+ Stream TTS audio for long text (>4096 chars).
167
+ Uses chunking and streaming for better UX.
168
+
169
+ Args:
170
+ request: Stream TTS request with text and voice
171
+ user: Current authenticated user
172
+ audio_service: Audio service instance
173
+
174
+ Returns:
175
+ Streaming audio response
176
+
177
+ Raises:
178
+ HTTPException: If generation fails
179
+ """
180
+ log.info(
181
+ "[SpeechAPI] TTS stream request from user=%s, text_len=%d",
182
+ user.get("user_id"),
183
+ len(request.input)
184
+ )
185
+
186
+ try:
187
+ # Validate input
188
+ if not request.input or not request.input.strip():
189
+ raise HTTPException(400, "Input text is required")
190
+
191
+ # Add max length validation to prevent abuse (100KB max for streaming)
192
+ if len(request.input) > 100000:
193
+ raise HTTPException(
194
+ 413,
195
+ "Text too long (max 100000 characters for streaming)"
196
+ )
197
+
198
+ async def audio_generator():
199
+ async for chunk in audio_service.stream_speech(
200
+ text=request.input,
201
+ voice=request.voice,
202
+ user_id=user.get("user_id", "anonymous"),
203
+ session_id=user.get("session_id", "default"),
204
+ app_name=user.get("app_name", "webui"),
205
+ provider=request.provider # Pass provider from request
206
+ ):
207
+ yield chunk
208
+
209
+ return StreamingResponse(
210
+ audio_generator(),
211
+ media_type="audio/mpeg",
212
+ headers={
213
+ "Content-Disposition": f"inline; filename=tts_stream_{request.runId or 'audio'}.mp3",
214
+ "Cache-Control": "no-cache"
215
+ }
216
+ )
217
+
218
+ except HTTPException:
219
+ raise
220
+ except Exception as e:
221
+ log.exception("[SpeechAPI] TTS stream error: %s", e)
222
+ raise HTTPException(500, f"TTS streaming failed: {str(e)}")
223
+
224
+
225
+ @router.get("/voices")
226
+ async def get_voices(
227
+ provider: Optional[str] = None, # NEW: Accept provider as query parameter
228
+ user: dict = Depends(get_current_user),
229
+ audio_service: AudioService = Depends(get_audio_service)
230
+ ):
231
+ """
232
+ Get available TTS voices based on configuration and provider.
233
+
234
+ Args:
235
+ provider: Optional provider filter (azure, gemini)
236
+ user: Current authenticated user
237
+ audio_service: Audio service instance
238
+
239
+ Returns:
240
+ JSON with available voices:
241
+ {
242
+ "voices": ["Kore", "Puck", "Zephyr", ...],
243
+ "default": "Kore"
244
+ }
245
+ """
246
+ log.debug("[SpeechAPI] Voices request from user=%s, provider=%s", user.get("user_id"), provider)
247
+
248
+ try:
249
+ voices = await audio_service.get_available_voices(provider=provider) # Pass provider
250
+
251
+ # Get default voice from config
252
+ config = audio_service.get_speech_config()
253
+ default_voice = config.get("voice", "Kore")
254
+
255
+ return {
256
+ "voices": voices,
257
+ "default": default_voice
258
+ }
259
+
260
+ except Exception as e:
261
+ log.exception("[SpeechAPI] Error getting voices: %s", e)
262
+ raise HTTPException(500, f"Failed to get voices: {str(e)}")
263
+
264
+
265
+ @router.get("/config")
266
+ async def get_speech_config(
267
+ user: dict = Depends(get_current_user),
268
+ audio_service: AudioService = Depends(get_audio_service)
269
+ ):
270
+ """
271
+ Get speech configuration for frontend initialization.
272
+
273
+ Args:
274
+ user: Current authenticated user
275
+ audio_service: Audio service instance
276
+
277
+ Returns:
278
+ JSON with speech configuration:
279
+ {
280
+ "sttExternal": true,
281
+ "ttsExternal": true,
282
+ "speechToText": true,
283
+ "textToSpeech": true,
284
+ "engineSTT": "external",
285
+ "engineTTS": "external",
286
+ "voice": "Kore",
287
+ "playbackRate": 1.0,
288
+ "cacheTTS": true,
289
+ ...
290
+ }
291
+ """
292
+ log.debug("[SpeechAPI] Config request from user=%s", user.get("user_id"))
293
+
294
+ try:
295
+ config = audio_service.get_speech_config()
296
+ return config
297
+
298
+ except Exception as e:
299
+ log.exception("[SpeechAPI] Error getting config: %s", e)
300
+ raise HTTPException(500, f"Failed to get config: {str(e)}")
301
+
302
+
303
+ @router.post("/voice-sample")
304
+ async def get_voice_sample(
305
+ voice: str = Form(...),
306
+ provider: Optional[str] = Form(None),
307
+ user: dict = Depends(get_current_user),
308
+ audio_service: AudioService = Depends(get_audio_service)
309
+ ):
310
+ """
311
+ Generate a sample audio for a specific voice to preview before selection.
312
+
313
+ Args:
314
+ voice: Voice name to sample
315
+ provider: Optional provider (azure, gemini)
316
+ user: Current authenticated user
317
+ audio_service: Audio service instance
318
+
319
+ Returns:
320
+ Audio data as MP3
321
+
322
+ Raises:
323
+ HTTPException: If generation fails
324
+ """
325
+ log.debug("[SpeechAPI] Voice sample request from user=%s, voice=%s, provider=%s",
326
+ user.get("user_id"), voice, provider)
327
+
328
+ try:
329
+ # Validate voice parameter
330
+ if not voice or not voice.strip():
331
+ raise HTTPException(400, "Voice parameter is required")
332
+
333
+ # Generate a sample text based on provider
334
+ sample_text = "Hello! This is a sample of my voice. I hope you find it pleasant to listen to."
335
+
336
+ audio_data = await audio_service.generate_speech(
337
+ text=sample_text,
338
+ voice=voice,
339
+ user_id=user.get("user_id", "anonymous"),
340
+ session_id=user.get("session_id", "default"),
341
+ app_name=user.get("app_name", "webui"),
342
+ message_id=f"voice_sample_{voice}",
343
+ provider=provider
344
+ )
345
+
346
+ return Response(
347
+ content=audio_data,
348
+ media_type="audio/mpeg"
349
+ )
350
+
351
+ except HTTPException:
352
+ raise
353
+ except Exception as e:
354
+ log.exception("[SpeechAPI] Voice sample error: %s", e)
355
+ raise HTTPException(500, f"Voice sample generation failed: {str(e)}")
@@ -5,12 +5,14 @@ API Router for Server-Sent Events (SSE) subscriptions.
5
5
  import logging
6
6
  import asyncio
7
7
  import json
8
- from fastapi import APIRouter, Depends, Request as FastAPIRequest, HTTPException, status
8
+ from fastapi import APIRouter, Depends, Request as FastAPIRequest, HTTPException, status, Query
9
+ from sqlalchemy.orm import Session as DBSession
9
10
 
10
11
  from sse_starlette.sse import EventSourceResponse
11
12
 
12
13
  from ....gateway.http_sse.sse_manager import SSEManager
13
- from ....gateway.http_sse.dependencies import get_sse_manager
14
+ from ....gateway.http_sse.dependencies import get_sse_manager, get_db
15
+ from ....gateway.http_sse.repository.task_repository import TaskRepository
14
16
 
15
17
  log = logging.getLogger(__name__)
16
18
  trace_logger = logging.getLogger("sam_trace")
@@ -23,16 +25,32 @@ router = APIRouter()
23
25
  async def subscribe_to_task_events(
24
26
  task_id: str,
25
27
  request: FastAPIRequest,
28
+ reconnect: bool = Query(False, description="Whether this is a reconnection attempt"),
29
+ last_event_timestamp: int = Query(0, description="Timestamp of last received event for replay"),
26
30
  sse_manager: SSEManager = Depends(get_sse_manager),
31
+ db: DBSession = Depends(get_db),
27
32
  ):
28
33
  """
29
34
  Establishes an SSE connection to receive real-time updates for a specific task.
35
+
36
+ Args:
37
+ task_id: The task to monitor
38
+ reconnect: If true, replay missed events before streaming live
39
+ last_event_timestamp: Timestamp of last received event (for replay)
30
40
  """
31
41
  log_prefix = "[GET /api/v1/sse/subscribe/%s] " % task_id
32
- log.debug("%sClient requesting SSE subscription.", log_prefix)
42
+ log.debug("%sClient requesting SSE subscription (reconnect=%s).", log_prefix, reconnect)
33
43
 
34
44
  connection_queue: asyncio.Queue = None
35
45
  try:
46
+ # Check if this is a background task
47
+ repo = TaskRepository()
48
+ task = repo.find_by_id(db, task_id)
49
+ is_background_task = task and task.background_execution_enabled
50
+
51
+ if is_background_task:
52
+ log.info("%sTask %s is a background task.", log_prefix, task_id)
53
+
36
54
  connection_queue = await sse_manager.create_sse_connection(task_id)
37
55
  log.debug("%sSSE connection queue created.", log_prefix)
38
56
 
@@ -42,6 +60,87 @@ async def subscribe_to_task_events(
42
60
  try:
43
61
  yield {"comment": "SSE connection established"}
44
62
  log.debug("%sSent initial SSE comment.", log_prefix)
63
+
64
+ # If reconnecting, replay missed events from database
65
+ # For background tasks, always replay ALL events from the beginning
66
+ # to ensure the frontend can reconstruct the full message content
67
+ # after a browser refresh
68
+ if reconnect:
69
+ replay_from_timestamp = last_event_timestamp if last_event_timestamp > 0 else 0
70
+
71
+ # For background tasks, always replay from the beginning
72
+ # This handles the case where the browser was refreshed and
73
+ # the accumulated message content was lost
74
+ if is_background_task:
75
+ replay_from_timestamp = 0
76
+ log.info("%sBackground task reconnection - replaying ALL events from beginning", log_prefix)
77
+ else:
78
+ log.info("%sReplaying events since timestamp %d", log_prefix, replay_from_timestamp)
79
+
80
+ task_with_events = repo.find_by_id_with_events(db, task_id)
81
+ if task_with_events:
82
+ _, events = task_with_events
83
+ # Use >= for timestamp 0 to include all events
84
+ missed_events = [e for e in events if e.created_time > replay_from_timestamp]
85
+ log.info("%sReplaying %d missed events", log_prefix, len(missed_events))
86
+
87
+ # For background tasks, filter out intermediate artifact update events
88
+ # to prevent duplicate artifacts in chat. Only keep the final task response
89
+ # which contains the complete artifact list.
90
+ if is_background_task:
91
+ # Find if there's a final task response
92
+ has_final_response = any(
93
+ e.direction == "response" and
94
+ "result" in e.payload and
95
+ e.payload.get("result", {}).get("kind") == "task"
96
+ for e in missed_events
97
+ )
98
+
99
+ if has_final_response:
100
+ # Filter out artifact-update events since the final response contains all artifacts
101
+ filtered_events = []
102
+ for e in missed_events:
103
+ if e.direction == "response" and "result" in e.payload:
104
+ result = e.payload.get("result", {})
105
+ if result.get("kind") == "artifact-update":
106
+ log.debug(
107
+ "%sFiltering out intermediate artifact-update event during replay",
108
+ log_prefix
109
+ )
110
+ continue
111
+ filtered_events.append(e)
112
+ missed_events = filtered_events
113
+ log.info(
114
+ "%sFiltered to %d events (removed intermediate artifact updates)",
115
+ log_prefix,
116
+ len(missed_events)
117
+ )
118
+
119
+ for event in missed_events:
120
+ # The payload is already a JSON-RPC response, just need to determine event type
121
+ # and yield it in the same format as live events
122
+ event_type = "status_update" # Default
123
+
124
+ # Determine event type from the payload structure
125
+ if event.direction == "response":
126
+ # Check if it's a final response (Task object) or status update
127
+ if "result" in event.payload:
128
+ result = event.payload.get("result", {})
129
+ if result.get("kind") == "task":
130
+ event_type = "final_response"
131
+ elif result.get("kind") == "status-update":
132
+ event_type = "status_update"
133
+ elif result.get("kind") == "artifact-update":
134
+ event_type = "artifact_update"
135
+
136
+ # Yield the event in SSE format
137
+ # The payload is already the complete JSON-RPC response
138
+ yield {
139
+ "event": event_type,
140
+ "data": json.dumps(event.payload)
141
+ }
142
+
143
+ log.info("%sFinished replaying missed events", log_prefix)
45
144
 
46
145
  loop_count = 0
47
146
  while True:
@@ -55,7 +154,16 @@ async def subscribe_to_task_events(
55
154
  "%sRequest disconnected status: %s", log_prefix, disconnected
56
155
  )
57
156
  if disconnected:
58
- log.info("%sClient disconnected. Breaking loop.", log_prefix)
157
+ if is_background_task:
158
+ log.info(
159
+ "%sClient disconnected from background task %s. Draining buffers and exiting SSE stream.",
160
+ log_prefix,
161
+ task_id
162
+ )
163
+ # For background tasks, we need to drain the buffers to prevent overflow
164
+ # The task will continue running, but we stop consuming events
165
+ else:
166
+ log.info("%sClient disconnected. Breaking loop.", log_prefix)
59
167
  break
60
168
 
61
169
  try:
@@ -135,6 +243,11 @@ async def subscribe_to_task_events(
135
243
  if connection_queue:
136
244
  await sse_manager.remove_sse_connection(task_id, connection_queue)
137
245
  log.info("%sRemoved SSE connection queue from manager.", log_prefix)
246
+
247
+ # If this was a background task, drain the buffer to prevent overflow
248
+ if is_background_task:
249
+ await sse_manager.drain_buffer_for_background_task(task_id)
250
+ log.info("%sDrained buffer for background task %s", log_prefix, task_id)
138
251
 
139
252
  return EventSourceResponse(event_generator())
140
253