solace-agent-mesh 1.11.2__py3-none-any.whl → 1.12.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (308) hide show
  1. solace_agent_mesh/agent/adk/callbacks.py +177 -10
  2. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +3 -0
  3. solace_agent_mesh/agent/adk/models/lite_llm.py +34 -16
  4. solace_agent_mesh/agent/adk/runner.py +66 -8
  5. solace_agent_mesh/agent/adk/setup.py +61 -26
  6. solace_agent_mesh/agent/protocol/event_handlers.py +48 -0
  7. solace_agent_mesh/agent/proxies/a2a/component.py +27 -0
  8. solace_agent_mesh/agent/sac/component.py +84 -2
  9. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +41 -22
  10. solace_agent_mesh/agent/tools/peer_agent_tool.py +19 -12
  11. solace_agent_mesh/agent/tools/tool_config_types.py +21 -1
  12. solace_agent_mesh/agent/utils/artifact_helpers.py +54 -0
  13. solace_agent_mesh/assets/docs/404.html +3 -3
  14. solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
  15. solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
  16. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
  17. solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
  18. solace_agent_mesh/assets/docs/assets/js/{3ac1795d.28b7c67b.js → 3ac1795d.dc006e20.js} +1 -1
  19. solace_agent_mesh/assets/docs/assets/js/3ff0015d.f08618fb.js +1 -0
  20. solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
  21. solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
  22. solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
  23. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
  24. solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
  25. solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
  26. solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
  27. solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
  28. solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
  29. solace_agent_mesh/assets/docs/assets/js/81a99df0.95be65d4.js +1 -0
  30. solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
  31. solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
  32. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
  33. solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
  34. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
  35. solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
  36. solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
  37. solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
  38. solace_agent_mesh/assets/docs/assets/js/f284c35a.08fab659.js +1 -0
  39. solace_agent_mesh/assets/docs/assets/js/main.b241af3e.js +2 -0
  40. solace_agent_mesh/assets/docs/assets/js/runtime~main.4ca7d2e2.js +1 -0
  41. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +4 -4
  42. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +4 -4
  43. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +4 -4
  44. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +4 -4
  45. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +4 -4
  46. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
  47. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +14 -12
  48. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +30 -9
  49. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +4 -4
  50. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +6 -4
  51. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +4 -4
  52. solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
  53. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +4 -4
  54. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +4 -4
  55. solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +4 -4
  56. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +4 -4
  57. solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +4 -4
  58. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +4 -4
  59. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +5 -5
  60. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +4 -4
  61. solace_agent_mesh/assets/docs/docs/documentation/deploying/{kubernetes-deployment → kubernetes}/index.html +6 -6
  62. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
  63. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +11 -6
  64. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +4 -4
  65. solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +4 -4
  66. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +4 -4
  67. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +4 -4
  68. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +23 -5
  69. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +4 -4
  70. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +4 -4
  71. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +4 -4
  72. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +4 -4
  73. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +4 -4
  74. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +4 -4
  75. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +4 -4
  76. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +17 -8
  77. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +4 -4
  78. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +4 -4
  79. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +4 -4
  80. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +4 -4
  81. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +4 -4
  82. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +4 -4
  83. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +5 -5
  84. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +4 -4
  85. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +4 -4
  86. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +4 -4
  87. solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +4 -4
  88. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +4 -4
  89. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +4 -4
  90. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +4 -4
  91. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +4 -4
  92. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +4 -4
  93. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +6 -5
  94. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +4 -4
  95. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +4 -4
  96. solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
  97. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +25 -4
  98. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +4 -4
  99. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +4 -4
  100. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +4 -4
  101. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +4 -4
  102. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +4 -4
  103. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +4 -4
  104. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +4 -4
  105. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +4 -4
  106. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +4 -4
  107. solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
  108. solace_agent_mesh/assets/docs/lunr-index-1767712284328.json +1 -0
  109. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  110. solace_agent_mesh/assets/docs/search-doc-1767712284328.json +1 -0
  111. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  112. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  113. solace_agent_mesh/cli/__init__.py +1 -1
  114. solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
  115. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
  116. solace_agent_mesh/cli/commands/init_cmd/env_step.py +29 -2
  117. solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
  118. solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
  119. solace_agent_mesh/cli/main.py +2 -0
  120. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-Dj3JtK42.js → authCallback-8Nihi8rv.js} +1 -1
  121. solace_agent_mesh/client/webui/frontend/static/assets/{client-ZKk9kEJ5.js → client-DYtZN8p-.js} +1 -1
  122. solace_agent_mesh/client/webui/frontend/static/assets/main-BYGUHQMk.js +435 -0
  123. solace_agent_mesh/client/webui/frontend/static/assets/main-D2CSH1bp.css +1 -0
  124. solace_agent_mesh/client/webui/frontend/static/assets/{vendor-BNV4kZN0.js → vendor-XBWAmrun.js} +106 -101
  125. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  126. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  127. solace_agent_mesh/client/webui/frontend/static/ui-version.json +1 -1
  128. solace_agent_mesh/common/a2a/types.py +1 -1
  129. solace_agent_mesh/common/agent_registry.py +38 -11
  130. solace_agent_mesh/common/data_parts.py +28 -0
  131. solace_agent_mesh/common/error_handlers.py +83 -0
  132. solace_agent_mesh/common/sam_events/event_service.py +2 -2
  133. solace_agent_mesh/config_portal/backend/common.py +2 -0
  134. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ZV-jX48T.js +103 -0
  135. solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-ba77705e.js → manifest-ce5bc5da.js} +1 -1
  136. solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
  137. solace_agent_mesh/core_a2a/service.py +3 -2
  138. solace_agent_mesh/gateway/adapter/base.py +28 -1
  139. solace_agent_mesh/gateway/adapter/types.py +9 -0
  140. solace_agent_mesh/gateway/base/auth_interface.py +103 -0
  141. solace_agent_mesh/gateway/base/component.py +68 -1
  142. solace_agent_mesh/gateway/generic/component.py +195 -30
  143. solace_agent_mesh/gateway/http_sse/app.py +23 -6
  144. solace_agent_mesh/gateway/http_sse/component.py +9 -61
  145. solace_agent_mesh/gateway/http_sse/dependencies.py +9 -51
  146. solace_agent_mesh/gateway/http_sse/main.py +28 -418
  147. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
  148. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +1 -1
  149. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +1 -1
  150. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +2 -2
  151. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +2 -2
  152. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +2 -2
  153. solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +1 -1
  154. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +1 -1
  155. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +1 -1
  156. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +1 -1
  157. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +4 -4
  158. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +2 -2
  159. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +16 -15
  160. solace_agent_mesh/gateway/http_sse/routers/auth.py +61 -132
  161. solace_agent_mesh/gateway/http_sse/routers/config.py +12 -8
  162. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +1 -1
  163. solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
  164. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +2 -2
  165. solace_agent_mesh/gateway/http_sse/routers/feedback.py +2 -2
  166. solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
  167. solace_agent_mesh/gateway/http_sse/routers/projects.py +2 -1
  168. solace_agent_mesh/gateway/http_sse/routers/prompts.py +2 -1
  169. solace_agent_mesh/gateway/http_sse/routers/sessions.py +3 -3
  170. solace_agent_mesh/gateway/http_sse/routers/speech.py +1 -1
  171. solace_agent_mesh/gateway/http_sse/routers/tasks.py +3 -2
  172. solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
  173. solace_agent_mesh/gateway/http_sse/routers/visualization.py +2 -1
  174. solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +1 -1
  175. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
  176. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
  177. solace_agent_mesh/gateway/http_sse/services/session_service.py +4 -4
  178. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +1 -1
  179. solace_agent_mesh/services/platform/__init__.py +23 -12
  180. solace_agent_mesh/services/platform/api/dependencies.py +23 -16
  181. solace_agent_mesh/services/platform/api/main.py +118 -43
  182. solace_agent_mesh/services/platform/api/routers/__init__.py +12 -3
  183. solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
  184. solace_agent_mesh/services/platform/app.py +101 -7
  185. solace_agent_mesh/services/platform/component.py +552 -33
  186. solace_agent_mesh/shared/__init__.py +14 -0
  187. solace_agent_mesh/shared/api/__init__.py +42 -0
  188. solace_agent_mesh/shared/auth/__init__.py +26 -0
  189. solace_agent_mesh/shared/auth/dependencies.py +204 -0
  190. solace_agent_mesh/shared/auth/middleware.py +291 -0
  191. solace_agent_mesh/shared/database/__init__.py +20 -0
  192. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
  193. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
  194. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
  195. solace_agent_mesh/shared/exceptions/__init__.py +36 -0
  196. solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +1 -1
  197. solace_agent_mesh/shared/utils/__init__.py +21 -0
  198. solace_agent_mesh/templates/platform.yaml +49 -0
  199. solace_agent_mesh/templates/webui.yaml +12 -3
  200. {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/METADATA +2 -1
  201. {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/RECORD +214 -258
  202. solace_agent_mesh/agent/adk/adk_llm.txt +0 -226
  203. solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
  204. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
  205. solace_agent_mesh/agent/adk/models/models_llm.txt +0 -189
  206. solace_agent_mesh/agent/agent_llm.txt +0 -369
  207. solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
  208. solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
  209. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
  210. solace_agent_mesh/agent/proxies/a2a/a2a_llm.txt +0 -190
  211. solace_agent_mesh/agent/proxies/base/base_llm.txt +0 -148
  212. solace_agent_mesh/agent/proxies/proxies_llm.txt +0 -283
  213. solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
  214. solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
  215. solace_agent_mesh/agent/testing/testing_llm.txt +0 -58
  216. solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
  217. solace_agent_mesh/agent/tools/tools_llm.txt +0 -276
  218. solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -275
  219. solace_agent_mesh/agent/utils/utils_llm.txt +0 -152
  220. solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
  221. solace_agent_mesh/assets/docs/assets/js/15ba94aa.92fea363.js +0 -1
  222. solace_agent_mesh/assets/docs/assets/js/240a0364.9ad94d1b.js +0 -1
  223. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
  224. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
  225. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2ddc75c0.js +0 -1
  226. solace_agent_mesh/assets/docs/assets/js/547e15cc.2f7790c1.js +0 -1
  227. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.90a87880.js +0 -1
  228. solace_agent_mesh/assets/docs/assets/js/64195356.c498c4d0.js +0 -1
  229. solace_agent_mesh/assets/docs/assets/js/66d4869e.b77431fc.js +0 -1
  230. solace_agent_mesh/assets/docs/assets/js/8024126c.fa0e7186.js +0 -1
  231. solace_agent_mesh/assets/docs/assets/js/81a99df0.2484b8d9.js +0 -1
  232. solace_agent_mesh/assets/docs/assets/js/9bb13469.b2333011.js +0 -1
  233. solace_agent_mesh/assets/docs/assets/js/ab9708a8.245ae0ef.js +0 -1
  234. solace_agent_mesh/assets/docs/assets/js/db5d6442.3daf1696.js +0 -1
  235. solace_agent_mesh/assets/docs/assets/js/e04b235d.52cb25ed.js +0 -1
  236. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.b1068f9b.js +0 -1
  237. solace_agent_mesh/assets/docs/assets/js/e6f9706b.4488e34c.js +0 -1
  238. solace_agent_mesh/assets/docs/assets/js/e92d0134.3bda61dd.js +0 -1
  239. solace_agent_mesh/assets/docs/assets/js/f284c35a.250993bf.js +0 -1
  240. solace_agent_mesh/assets/docs/assets/js/main.7acf7ace.js +0 -2
  241. solace_agent_mesh/assets/docs/assets/js/runtime~main.9e0813a2.js +0 -1
  242. solace_agent_mesh/assets/docs/lunr-index-1765810064709.json +0 -1
  243. solace_agent_mesh/assets/docs/search-doc-1765810064709.json +0 -1
  244. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
  245. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
  246. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
  247. solace_agent_mesh/client/webui/frontend/static/assets/main-BcUaNZ-Q.css +0 -1
  248. solace_agent_mesh/client/webui/frontend/static/assets/main-vjch4RYc.js +0 -435
  249. solace_agent_mesh/common/a2a/a2a_llm.txt +0 -175
  250. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
  251. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -445
  252. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
  253. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -330
  254. solace_agent_mesh/common/common_llm.txt +0 -230
  255. solace_agent_mesh/common/common_llm_detail.txt +0 -2562
  256. solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
  257. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
  258. solace_agent_mesh/common/sac/sac_llm.txt +0 -71
  259. solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
  260. solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
  261. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
  262. solace_agent_mesh/common/services/providers/providers_llm.txt +0 -81
  263. solace_agent_mesh/common/services/services_llm.txt +0 -368
  264. solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
  265. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
  266. solace_agent_mesh/common/utils/utils_llm.txt +0 -335
  267. solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
  268. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DiOiAjzL.js +0 -103
  269. solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
  270. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
  271. solace_agent_mesh/gateway/base/base_llm.txt +0 -226
  272. solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
  273. solace_agent_mesh/gateway/gateway_llm.txt +0 -369
  274. solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
  275. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -345
  276. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -161
  277. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
  278. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
  279. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
  280. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -221
  281. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -257
  282. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -308
  283. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -450
  284. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -133
  285. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -123
  286. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -312
  287. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -303
  288. solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
  289. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -319
  290. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
  291. solace_agent_mesh/llm.txt +0 -228
  292. solace_agent_mesh/llm_detail.txt +0 -2835
  293. solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
  294. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
  295. solace_agent_mesh/templates/templates_llm.txt +0 -147
  296. /solace_agent_mesh/assets/docs/assets/js/{main.7acf7ace.js.LICENSE.txt → main.b241af3e.js.LICENSE.txt} +0 -0
  297. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
  298. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
  299. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
  300. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
  301. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
  302. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
  303. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
  304. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
  305. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
  306. {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/WHEEL +0 -0
  307. {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/entry_points.txt +0 -0
  308. {solace_agent_mesh-1.11.2.dist-info → solace_agent_mesh-1.12.0.dist-info}/licenses/LICENSE +0 -0
@@ -5,44 +5,92 @@ Hosts the FastAPI REST API server for platform configuration management.
5
5
 
6
6
  import logging
7
7
  import threading
8
+ import json
9
+ from typing import Any, Dict
8
10
 
9
11
  import uvicorn
10
- from solace_ai_connector.components.component_base import ComponentBase
12
+ from solace_ai_connector.common.message import Message as SolaceMessage
13
+ from solace_agent_mesh.common.sac.sam_component_base import SamComponentBase
11
14
  from solace_agent_mesh.common.middleware.config_resolver import ConfigResolver
15
+ from solace_agent_mesh.core_a2a.service import CoreA2AService
16
+ from solace_agent_mesh.common import a2a
17
+ from solace_agent_mesh.common.constants import (
18
+ HEALTH_CHECK_INTERVAL_SECONDS,
19
+ HEALTH_CHECK_TTL_SECONDS,
20
+ )
21
+ from a2a.types import AgentCard
12
22
 
13
23
  log = logging.getLogger(__name__)
14
24
 
15
25
 
16
26
  class _StubSessionManager:
17
27
  """
18
- Minimal stub for SessionManager to satisfy gateway dependencies.
28
+ Minimal stub for SessionManager to satisfy legacy router dependencies.
19
29
 
20
- Platform service doesn't have sessions, but webui_backend routers
21
- expect a SessionManager for user_id resolution. This stub provides
22
- just enough to make get_user_id work when OAuth middleware sets
23
- request.state.user.
30
+ Platform service doesn't have chat sessions, but webui_backend routers
31
+ (originally designed for WebUI gateway) expect a SessionManager.
32
+ This stub provides minimal compatibility.
24
33
  """
25
- def __init__(self, use_authorization: bool):
26
- self.use_authorization = use_authorization
34
+ pass
27
35
 
28
36
 
29
37
  info = {
30
38
  "class_name": "PlatformServiceComponent",
31
39
  "description": (
32
- "Platform Service Component - REST API for platform configuration management. "
33
- "NOT a gateway - no session management, no A2A communication, no artifacts."
40
+ "Platform Service Component - REST API for platform management (agents, connectors, deployments). "
41
+ "This is a SERVICE, not a gateway - services provide internal platform functionality, "
42
+ "while gateways handle external communication channels."
34
43
  ),
35
44
  }
36
45
 
37
46
 
38
- class PlatformServiceComponent(ComponentBase):
47
+ class PlatformServiceComponent(SamComponentBase):
39
48
  """
40
- Platform Service Component
49
+ Platform Service Component - Management plane for SAM platform.
50
+
51
+ Architecture distinction:
52
+ - SERVICE: Provides internal platform functionality (this component)
53
+ - GATEWAY: Handles external communication channels (http_sse, slack, webhook, etc.)
54
+
55
+ Responsibilities:
56
+ - REST API for platform configuration management
57
+ - Agent Builder CRUD operations
58
+ - Connector management
59
+ - Deployment orchestration
60
+ - Deployer heartbeat monitoring
61
+ - Background deployment status checking
41
62
 
42
63
  Key characteristics:
43
- - Pure REST API with CRUD operations on platform database
64
+ - No user chat sessions (services don't interact with end users)
65
+ - Uses direct messaging (publishes commands to deployer, receives heartbeats)
66
+ - Has agent registry (for deployment monitoring, not chat orchestration)
67
+ - Independent from WebUI gateway
68
+ - NOT A2A communication (deployer is a service, not an agent)
44
69
  """
45
70
 
71
+ HEALTH_CHECK_TIMER_ID = "platform_agent_health_check"
72
+
73
+ def get_config(self, key: str, default: Any = None) -> Any:
74
+ """
75
+ Override get_config to look inside nested 'app_config' dictionary.
76
+
77
+ PlatformServiceApp places configuration in component_config['app_config'],
78
+ following the same pattern as BaseGatewayApp.
79
+
80
+ Args:
81
+ key: Configuration key to retrieve
82
+ default: Default value if key not found
83
+
84
+ Returns:
85
+ Configuration value or default
86
+ """
87
+ if "app_config" in self.component_config:
88
+ value = self.component_config["app_config"].get(key)
89
+ if value is not None:
90
+ return value
91
+
92
+ return super().get_config(key, default)
93
+
46
94
  def __init__(self, **kwargs):
47
95
  """
48
96
  Initialize the PlatformServiceComponent.
@@ -50,28 +98,47 @@ class PlatformServiceComponent(ComponentBase):
50
98
  Retrieves configuration, initializes FastAPI server state,
51
99
  and starts the FastAPI/Uvicorn server.
52
100
  """
101
+ # Initialize SamComponentBase (provides namespace, max_message_size, async loop)
53
102
  super().__init__(info, **kwargs)
54
103
  log.info("%s Initializing Platform Service Component...", self.log_identifier)
55
104
 
105
+ # Note: self.namespace is already set by SamComponentBase
106
+ # Note: self.max_message_size_bytes is already set by SamComponentBase
107
+
56
108
  try:
57
- # Retrieve configuration
58
- self.namespace = self.get_config("namespace")
109
+ # Retrieve Platform Service specific configuration
59
110
  self.database_url = self.get_config("database_url")
60
111
  self.fastapi_host = self.get_config("fastapi_host", "127.0.0.1")
61
112
  self.fastapi_port = int(self.get_config("fastapi_port", 8001))
113
+ self.fastapi_https_port = int(self.get_config("fastapi_https_port", 8444))
114
+ self.ssl_keyfile = self.get_config("ssl_keyfile", "")
115
+ self.ssl_certfile = self.get_config("ssl_certfile", "")
116
+ self.ssl_keyfile_password = self.get_config("ssl_keyfile_password", "")
62
117
  self.cors_allowed_origins = self.get_config("cors_allowed_origins", ["*"])
63
118
 
64
- # OAuth2 configuration
65
- self.external_auth_service_url = self.get_config("external_auth_service_url")
66
- self.external_auth_provider = self.get_config("external_auth_provider", "azure")
67
- self.use_authorization = self.get_config("use_authorization", True)
119
+ # OAuth2 configuration (enterprise feature - defaults to community mode)
120
+ self.external_auth_service_url = self.get_config("external_auth_service_url", "")
121
+ self.external_auth_provider = self.get_config("external_auth_provider", "generic")
122
+
123
+ # Background task configuration
124
+ self.deployment_timeout_minutes = self.get_config("deployment_timeout_minutes", 5)
125
+ self.heartbeat_timeout_seconds = self.get_config("heartbeat_timeout_seconds", 90)
126
+ self.deployment_check_interval_seconds = self.get_config("deployment_check_interval_seconds", 60)
127
+
128
+ # Agent health check configuration (for removing expired agents from registry)
129
+ self.health_check_interval_seconds = self.get_config(
130
+ "health_check_interval_seconds", HEALTH_CHECK_INTERVAL_SECONDS
131
+ )
132
+ self.health_check_ttl_seconds = self.get_config(
133
+ "health_check_ttl_seconds", HEALTH_CHECK_TTL_SECONDS
134
+ )
68
135
 
69
136
  log.info(
70
137
  "%s Platform service configuration retrieved (Host: %s, Port: %d, Auth: %s).",
71
138
  self.log_identifier,
72
139
  self.fastapi_host,
73
140
  self.fastapi_port,
74
- "enabled" if self.use_authorization else "disabled",
141
+ "enabled" if self.get_config("frontend_use_authorization", False) else "disabled",
75
142
  )
76
143
  except Exception as e:
77
144
  log.error("%s Failed to retrieve configuration: %s", self.log_identifier, e)
@@ -85,16 +152,59 @@ class PlatformServiceComponent(ComponentBase):
85
152
  # Config resolver (permissive default - allows all features/scopes)
86
153
  self.config_resolver = ConfigResolver()
87
154
 
88
- # Gateway compatibility attributes
89
- # These allow webui_backend routers (designed for gateway) to work with platform service
90
- # self.component_config = {"app_config": {}}
91
- self.session_manager = _StubSessionManager(use_authorization=self.use_authorization)
155
+ # Legacy router compatibility
156
+ # webui_backend routers were originally designed for WebUI gateway context
157
+ # but now work with Platform Service via dependency abstraction
158
+ self.session_manager = _StubSessionManager()
159
+
160
+ # Agent discovery (like BaseGatewayComponent)
161
+ # Initialize here so CoreA2AService can use it
162
+ from solace_agent_mesh.common.agent_registry import AgentRegistry
163
+ self.agent_registry = AgentRegistry()
164
+ self.core_a2a_service = CoreA2AService(
165
+ agent_registry=self.agent_registry,
166
+ namespace=self.namespace,
167
+ component_id="Platform"
168
+ )
169
+ log.info("%s Agent discovery service initialized", self.log_identifier)
170
+
171
+ # Background task state (for heartbeat monitoring and deployment status checking)
172
+ # Note: agent_registry already initialized above
173
+ self.heartbeat_tracker = None
174
+ self.heartbeat_listener = None
175
+ self.background_scheduler = None
176
+ self.background_tasks_thread = None
177
+
178
+ # Direct message publisher for deployer commands
179
+ self.direct_publisher = None
92
180
 
93
181
  log.info("%s Platform Service Component initialized.", self.log_identifier)
94
182
 
95
- # Start FastAPI server
183
+ # Note: FastAPI server, direct publisher, and background tasks are started
184
+ # in _late_init() after SamComponentBase.run() is called and broker is ready
185
+
186
+ def _late_init(self):
187
+ """
188
+ Late initialization called by SamComponentBase.run() after broker is ready.
189
+
190
+ This is the proper place to initialize services that require broker connectivity:
191
+ - FastAPI server (with startup event for background tasks)
192
+ - Direct message publisher (for deployer commands)
193
+ - Agent health check timer (for removing expired agents from registry)
194
+ """
195
+ log.info("%s Starting late initialization (broker-dependent services)...", self.log_identifier)
196
+
197
+ # Initialize direct message publisher for deployer commands
198
+ self._init_direct_publisher()
199
+
200
+ # Start FastAPI server (background tasks started via FastAPI startup event)
96
201
  self._start_fastapi_server()
97
202
 
203
+ # Schedule agent health checks to remove expired agents from registry
204
+ self._schedule_agent_health_check()
205
+
206
+ log.info("%s Late initialization complete", self.log_identifier)
207
+
98
208
  def _start_fastapi_server(self):
99
209
  """
100
210
  Start the FastAPI/Uvicorn server in a separate background thread.
@@ -127,13 +237,45 @@ class PlatformServiceComponent(ComponentBase):
127
237
  # Setup dependencies (idempotent - safe to call multiple times)
128
238
  setup_dependencies(self, self.database_url)
129
239
 
130
- # Create uvicorn configuration
240
+ # Register startup event for background tasks
241
+ @self.fastapi_app.on_event("startup")
242
+ async def start_background_tasks():
243
+ try:
244
+ from solace_agent_mesh_enterprise.init_enterprise import start_platform_background_tasks
245
+
246
+ log.info("%s Starting enterprise platform background tasks...", self.log_identifier)
247
+ await start_platform_background_tasks(self)
248
+ log.info("%s Enterprise platform background tasks started", self.log_identifier)
249
+ except ImportError:
250
+ log.info(
251
+ "%s Enterprise package not available - no background tasks to start",
252
+ self.log_identifier
253
+ )
254
+ except Exception as e:
255
+ log.error(
256
+ "%s Failed to start enterprise background tasks: %s",
257
+ self.log_identifier,
258
+ e,
259
+ exc_info=True
260
+ )
261
+
262
+ # Determine port based on SSL configuration
263
+ port = (
264
+ self.fastapi_https_port
265
+ if self.ssl_keyfile and self.ssl_certfile
266
+ else self.fastapi_port
267
+ )
268
+
269
+ # Create uvicorn configuration with SSL support
131
270
  config = uvicorn.Config(
132
271
  app=self.fastapi_app,
133
272
  host=self.fastapi_host,
134
- port=self.fastapi_port,
273
+ port=port,
135
274
  log_level="warning",
136
275
  lifespan="on",
276
+ ssl_keyfile=self.ssl_keyfile if self.ssl_keyfile else None,
277
+ ssl_certfile=self.ssl_certfile if self.ssl_certfile else None,
278
+ ssl_keyfile_password=self.ssl_keyfile_password if self.ssl_keyfile_password else None,
137
279
  log_config=None,
138
280
  )
139
281
  self.uvicorn_server = uvicorn.Server(config)
@@ -145,11 +287,15 @@ class PlatformServiceComponent(ComponentBase):
145
287
  name="PlatformService_FastAPI_Thread",
146
288
  )
147
289
  self.fastapi_thread.start()
290
+
291
+ # Log with correct protocol
292
+ protocol = "https" if self.ssl_keyfile and self.ssl_certfile else "http"
148
293
  log.info(
149
- "%s FastAPI/Uvicorn server starting in background thread on http://%s:%d",
294
+ "%s FastAPI/Uvicorn server starting in background thread on %s://%s:%d",
150
295
  self.log_identifier,
296
+ protocol,
151
297
  self.fastapi_host,
152
- self.fastapi_port,
298
+ port,
153
299
  )
154
300
 
155
301
  except Exception as e:
@@ -160,17 +306,236 @@ class PlatformServiceComponent(ComponentBase):
160
306
  )
161
307
  raise
162
308
 
309
+ def _init_direct_publisher(self):
310
+ """
311
+ Initialize direct message publisher for deployer communication.
312
+
313
+ Platform Service sends deployment commands directly to deployer:
314
+ - {namespace}/deployer/agent/{id}/deploy
315
+ - {namespace}/deployer/agent/{id}/update
316
+ - {namespace}/deployer/agent/{id}/undeploy
317
+
318
+ Uses direct publishing (not A2A protocol) since deployer is a
319
+ standalone service, not an A2A agent.
320
+
321
+ Called from _late_init() and lazily from publish_a2a() if needed.
322
+ Uses SAC's existing broker connection via the BrokerOutput component.
323
+ """
324
+ try:
325
+ main_app = self.get_app()
326
+ if not main_app or not main_app.flows:
327
+ log.info(
328
+ "%s App flows not yet available - direct publisher will be initialized later",
329
+ self.log_identifier
330
+ )
331
+ return
332
+
333
+ # Find BrokerOutput component in the flow (same pattern as App.send_message)
334
+ broker_output = None
335
+ flow = main_app.flows[0]
336
+ if flow.component_groups:
337
+ for group in reversed(flow.component_groups):
338
+ if group:
339
+ comp = group[0]
340
+ if comp.module_info.get("class_name") == "BrokerOutput":
341
+ broker_output = comp
342
+ break
343
+
344
+ if not broker_output or not hasattr(broker_output, 'messaging_service'):
345
+ log.info(
346
+ "%s BrokerOutput component not ready - direct publisher will be initialized later",
347
+ self.log_identifier
348
+ )
349
+ return
350
+
351
+ self._messaging_service = broker_output.messaging_service.messaging_service
352
+ self.direct_publisher = self._messaging_service.create_direct_message_publisher_builder().build()
353
+ self.direct_publisher.start()
354
+
355
+ log.info("%s Direct message publisher initialized for deployer commands", self.log_identifier)
356
+
357
+ except Exception as e:
358
+ log.warning(
359
+ "%s Could not initialize direct publisher: %s (deployment commands will not work)",
360
+ self.log_identifier,
361
+ e
362
+ )
363
+
364
+ async def _handle_message_async(self, message, topic: str) -> None:
365
+ """
366
+ Handle incoming broker messages asynchronously (required by SamComponentBase).
367
+
368
+ Processes agent discovery messages and updates AgentRegistry.
369
+
370
+ Args:
371
+ message: The broker message
372
+ topic: The topic the message was received on
373
+ """
374
+ log.debug(
375
+ "%s Received async message on topic: %s",
376
+ self.log_identifier,
377
+ topic,
378
+ )
379
+
380
+ processed_successfully = False
381
+
382
+ try:
383
+ if a2a.topic_matches_subscription(
384
+ topic, a2a.get_discovery_topic(self.namespace)
385
+ ):
386
+ payload = message.get_payload()
387
+
388
+ # Parse JSON if payload is string/bytes (defensive coding)
389
+ if isinstance(payload, bytes):
390
+ payload = json.loads(payload.decode('utf-8'))
391
+ elif isinstance(payload, str):
392
+ payload = json.loads(payload)
393
+ # else: payload is already a dict (SAC framework auto-parses)
394
+
395
+ processed_successfully = self._handle_discovery_message(payload)
396
+ else:
397
+ log.debug(
398
+ "%s Ignoring message on non-discovery topic: %s",
399
+ self.log_identifier,
400
+ topic,
401
+ )
402
+ processed_successfully = True
403
+
404
+ except Exception as e:
405
+ log.error(
406
+ "%s Error handling async message on topic %s: %s",
407
+ self.log_identifier,
408
+ topic,
409
+ e,
410
+ exc_info=True
411
+ )
412
+ processed_successfully = False
413
+ finally:
414
+ # Acknowledge message (like BaseGatewayComponent pattern)
415
+ if hasattr(message, 'call_acknowledgements'):
416
+ try:
417
+ if processed_successfully:
418
+ message.call_acknowledgements()
419
+ else:
420
+ message.call_negative_acknowledgements()
421
+ except Exception as ack_error:
422
+ log.warning(
423
+ "%s Error acknowledging message: %s",
424
+ self.log_identifier,
425
+ ack_error
426
+ )
427
+
428
+ def _handle_discovery_message(self, payload: Dict) -> bool:
429
+ """
430
+ Handle incoming agent discovery messages.
431
+
432
+ Follows the same pattern as BaseGatewayComponent for consistency.
433
+
434
+ Args:
435
+ payload: The message payload dictionary
436
+
437
+ Returns:
438
+ True if processed successfully, False otherwise
439
+ """
440
+ try:
441
+ agent_card = AgentCard(**payload)
442
+ self.core_a2a_service.process_discovery_message(agent_card)
443
+ log.debug(
444
+ "%s Processed agent discovery: %s",
445
+ self.log_identifier,
446
+ agent_card.name
447
+ )
448
+ return True
449
+ except Exception as e:
450
+ log.error(
451
+ "%s Failed to process discovery message: %s. Payload: %s",
452
+ self.log_identifier,
453
+ e,
454
+ payload,
455
+ exc_info=True
456
+ )
457
+ return False
458
+
459
+ def _get_component_id(self) -> str:
460
+ """
461
+ Return unique identifier for this component (required by SamComponentBase).
462
+
463
+ Returns:
464
+ Component identifier string
465
+ """
466
+ return "platform_service"
467
+
468
+ def _get_component_type(self) -> str:
469
+ """
470
+ Return component type (required by SamComponentBase).
471
+
472
+ Returns:
473
+ Component type string
474
+ """
475
+ return "service"
476
+
477
+ def _pre_async_cleanup(self) -> None:
478
+ """
479
+ Cleanup before async operations stop (required by SamComponentBase).
480
+
481
+ Platform Service doesn't have async-specific resources to clean up here.
482
+ Main cleanup happens in cleanup() method.
483
+ """
484
+ pass
485
+
163
486
  def cleanup(self):
164
487
  """
165
488
  Gracefully shut down the Platform Service Component.
166
489
 
167
490
  This method:
168
- 1. Signals the uvicorn server to exit
169
- 2. Waits for the FastAPI thread to finish
170
- 3. Calls parent cleanup
491
+ 1. Stops direct message publisher
492
+ 2. Stops background tasks (heartbeat listener, deployment checker)
493
+ 3. Stops agent registry
494
+ 4. Signals the uvicorn server to exit
495
+ 5. Waits for the FastAPI thread to finish
496
+ 6. Calls parent cleanup
171
497
  """
172
498
  log.info("%s Cleaning up Platform Service Component...", self.log_identifier)
173
499
 
500
+ # Stop direct publisher
501
+ if self.direct_publisher:
502
+ try:
503
+ self.direct_publisher.terminate()
504
+ log.info("%s Direct message publisher stopped", self.log_identifier)
505
+ except Exception as e:
506
+ log.warning("%s Error stopping direct publisher: %s", self.log_identifier, e)
507
+
508
+ # Stop background scheduler
509
+ if self.background_scheduler:
510
+ try:
511
+ import asyncio
512
+ loop = asyncio.new_event_loop()
513
+ asyncio.set_event_loop(loop)
514
+ loop.run_until_complete(self.background_scheduler.stop())
515
+ log.info("%s Background scheduler stopped", self.log_identifier)
516
+ except Exception as e:
517
+ log.warning("%s Error stopping background scheduler: %s", self.log_identifier, e)
518
+
519
+ # Stop heartbeat listener
520
+ if self.heartbeat_listener:
521
+ try:
522
+ self.heartbeat_listener.stop()
523
+ log.info("%s Heartbeat listener stopped", self.log_identifier)
524
+ except Exception as e:
525
+ log.warning("%s Error stopping heartbeat listener: %s", self.log_identifier, e)
526
+
527
+ # Cancel health check timer before clearing registry
528
+ self.cancel_timer(self.HEALTH_CHECK_TIMER_ID)
529
+ log.info("%s Health check timer cancelled", self.log_identifier)
530
+
531
+ # Stop agent registry
532
+ if self.agent_registry:
533
+ try:
534
+ self.agent_registry.clear()
535
+ log.info("%s Agent registry stopped", self.log_identifier)
536
+ except Exception as e:
537
+ log.warning("%s Error stopping agent registry: %s", self.log_identifier, e)
538
+
174
539
  # Signal uvicorn to shutdown
175
540
  if self.uvicorn_server:
176
541
  self.uvicorn_server.should_exit = True
@@ -187,7 +552,7 @@ class PlatformServiceComponent(ComponentBase):
187
552
  self.log_identifier,
188
553
  )
189
554
 
190
- # Call parent cleanup
555
+ # Call SamComponentBase cleanup (stops async loop and threads)
191
556
  super().cleanup()
192
557
  log.info("%s Platform Service Component cleanup finished.", self.log_identifier)
193
558
 
@@ -233,3 +598,157 @@ class PlatformServiceComponent(ComponentBase):
233
598
  Stub SessionManager instance.
234
599
  """
235
600
  return self.session_manager
601
+
602
+ def get_heartbeat_tracker(self):
603
+ """
604
+ Return the heartbeat tracker instance.
605
+
606
+ Used by deployer status endpoint to check if deployer is online.
607
+
608
+ Returns:
609
+ HeartbeatTracker instance if initialized, None otherwise.
610
+ """
611
+ return self.heartbeat_tracker
612
+
613
+ def get_agent_registry(self):
614
+ """
615
+ Return the agent registry instance.
616
+
617
+ Used for deployment status monitoring.
618
+
619
+ Returns:
620
+ AgentRegistry instance if initialized, None otherwise.
621
+ """
622
+ return self.agent_registry
623
+
624
+ def _schedule_agent_health_check(self):
625
+ """
626
+ Schedule periodic agent health checks to remove expired agents from registry.
627
+
628
+ This is essential for deployment status checking - when an agent is undeployed,
629
+ the deployment status checker needs to see the agent removed from the registry
630
+ to mark the undeploy as successful.
631
+ """
632
+ if self.health_check_interval_seconds > 0:
633
+ log.info(
634
+ "%s Scheduling agent health check every %d seconds (TTL: %d seconds)",
635
+ self.log_identifier,
636
+ self.health_check_interval_seconds,
637
+ self.health_check_ttl_seconds,
638
+ )
639
+ self.add_timer(
640
+ delay_ms=self.health_check_interval_seconds * 1000,
641
+ timer_id=self.HEALTH_CHECK_TIMER_ID,
642
+ interval_ms=self.health_check_interval_seconds * 1000,
643
+ callback=lambda timer_data: self._check_agent_health(),
644
+ )
645
+ else:
646
+ log.warning(
647
+ "%s Agent health check disabled (interval=%d). "
648
+ "Agents will not be automatically removed from registry when they stop sending heartbeats.",
649
+ self.log_identifier,
650
+ self.health_check_interval_seconds,
651
+ )
652
+
653
+ def _check_agent_health(self):
654
+ """
655
+ Check agent health and remove expired agents from registry.
656
+
657
+ Called periodically by the health check timer. Iterates through all
658
+ registered agents and removes any whose TTL has expired (i.e., they
659
+ haven't sent a heartbeat recently).
660
+ """
661
+ log.debug("%s Performing agent health check...", self.log_identifier)
662
+
663
+ agent_names = self.agent_registry.get_agent_names()
664
+ total_agents = len(agent_names)
665
+ agents_removed = 0
666
+
667
+ for agent_name in agent_names:
668
+ is_expired, time_since_last_seen = self.agent_registry.check_ttl_expired(
669
+ agent_name, self.health_check_ttl_seconds
670
+ )
671
+
672
+ if is_expired:
673
+ log.warning(
674
+ "%s Agent '%s' TTL expired (last seen: %d seconds ago, TTL: %d seconds). Removing from registry.",
675
+ self.log_identifier,
676
+ agent_name,
677
+ time_since_last_seen,
678
+ self.health_check_ttl_seconds,
679
+ )
680
+ self.agent_registry.remove_agent(agent_name)
681
+ agents_removed += 1
682
+
683
+ if agents_removed > 0:
684
+ log.info(
685
+ "%s Agent health check complete: %d/%d agents removed",
686
+ self.log_identifier,
687
+ agents_removed,
688
+ total_agents,
689
+ )
690
+ else:
691
+ log.debug(
692
+ "%s Agent health check complete: %d agents, all healthy",
693
+ self.log_identifier,
694
+ total_agents,
695
+ )
696
+
697
+ def publish_a2a(
698
+ self, topic: str, payload: dict, user_properties: dict | None = None
699
+ ):
700
+ """
701
+ Publish direct message to deployer (not A2A protocol).
702
+
703
+ Platform Service sends deployment commands directly to deployer service.
704
+ This is service-to-service communication, not agent-to-agent protocol.
705
+
706
+ Commands sent to:
707
+ - {namespace}/deployer/agent/{agent_id}/deploy
708
+ - {namespace}/deployer/agent/{agent_id}/update
709
+ - {namespace}/deployer/agent/{agent_id}/undeploy
710
+
711
+ Args:
712
+ topic: Message topic
713
+ payload: Message payload dictionary (will be JSON-serialized)
714
+ user_properties: Optional user properties (not used by deployer)
715
+
716
+ Raises:
717
+ Exception: If publishing fails
718
+ """
719
+ import json
720
+ from solace.messaging.resources.topic import Topic
721
+
722
+ log.debug("%s Publishing deployer command to topic: %s", self.log_identifier, topic)
723
+
724
+ try:
725
+ if not self.direct_publisher:
726
+ self._init_direct_publisher()
727
+ if not self.direct_publisher:
728
+ raise RuntimeError("Direct publisher not initialized")
729
+
730
+ # Serialize payload to JSON and convert to bytearray
731
+ message_body = json.dumps(payload)
732
+ message_bytes = bytearray(message_body.encode("utf-8"))
733
+
734
+ # Publish directly to topic
735
+ self.direct_publisher.publish(
736
+ message=message_bytes,
737
+ destination=Topic.of(topic)
738
+ )
739
+
740
+ log.debug(
741
+ "%s Successfully published deployer command to topic: %s (payload size: %d bytes)",
742
+ self.log_identifier,
743
+ topic,
744
+ len(message_body)
745
+ )
746
+
747
+ except Exception as e:
748
+ log.error(
749
+ "%s Failed to publish deployer command: %s",
750
+ self.log_identifier,
751
+ e,
752
+ exc_info=True
753
+ )
754
+ raise