solace-agent-mesh 1.6.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 (481) 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/app_llm_agent.py +26 -0
  7. solace_agent_mesh/agent/adk/artifacts/filesystem_artifact_service.py +165 -1
  8. solace_agent_mesh/agent/adk/artifacts/s3_artifact_service.py +163 -0
  9. solace_agent_mesh/agent/adk/callbacks.py +852 -109
  10. solace_agent_mesh/agent/adk/embed_resolving_mcp_toolset.py +234 -36
  11. solace_agent_mesh/agent/adk/intelligent_mcp_callbacks.py +52 -5
  12. solace_agent_mesh/agent/adk/mcp_content_processor.py +1 -1
  13. solace_agent_mesh/agent/adk/models/lite_llm.py +77 -21
  14. solace_agent_mesh/agent/adk/models/oauth2_token_manager.py +24 -137
  15. solace_agent_mesh/agent/adk/runner.py +85 -20
  16. solace_agent_mesh/agent/adk/schema_migration.py +88 -0
  17. solace_agent_mesh/agent/adk/services.py +94 -18
  18. solace_agent_mesh/agent/adk/setup.py +281 -65
  19. solace_agent_mesh/agent/adk/stream_parser.py +231 -37
  20. solace_agent_mesh/agent/adk/tool_wrapper.py +3 -0
  21. solace_agent_mesh/agent/protocol/event_handlers.py +472 -137
  22. solace_agent_mesh/agent/proxies/a2a/app.py +3 -2
  23. solace_agent_mesh/agent/proxies/a2a/component.py +572 -75
  24. solace_agent_mesh/agent/proxies/a2a/config.py +80 -4
  25. solace_agent_mesh/agent/proxies/base/app.py +3 -2
  26. solace_agent_mesh/agent/proxies/base/component.py +188 -22
  27. solace_agent_mesh/agent/proxies/base/proxy_task_context.py +3 -1
  28. solace_agent_mesh/agent/sac/app.py +91 -3
  29. solace_agent_mesh/agent/sac/component.py +591 -157
  30. solace_agent_mesh/agent/sac/patch_adk.py +8 -16
  31. solace_agent_mesh/agent/sac/task_execution_context.py +146 -4
  32. solace_agent_mesh/agent/tools/__init__.py +3 -0
  33. solace_agent_mesh/agent/tools/audio_tools.py +3 -3
  34. solace_agent_mesh/agent/tools/builtin_artifact_tools.py +710 -171
  35. solace_agent_mesh/agent/tools/deep_research_tools.py +2161 -0
  36. solace_agent_mesh/agent/tools/dynamic_tool.py +2 -0
  37. solace_agent_mesh/agent/tools/peer_agent_tool.py +82 -15
  38. solace_agent_mesh/agent/tools/time_tools.py +126 -0
  39. solace_agent_mesh/agent/tools/tool_config_types.py +57 -2
  40. solace_agent_mesh/agent/tools/web_search_tools.py +279 -0
  41. solace_agent_mesh/agent/tools/web_tools.py +125 -17
  42. solace_agent_mesh/agent/utils/artifact_helpers.py +248 -6
  43. solace_agent_mesh/agent/utils/context_helpers.py +17 -0
  44. solace_agent_mesh/assets/docs/404.html +6 -6
  45. solace_agent_mesh/assets/docs/assets/css/{styles.906a1503.css → styles.8162edfb.css} +1 -1
  46. solace_agent_mesh/assets/docs/assets/js/05749d90.19ac4f35.js +1 -0
  47. solace_agent_mesh/assets/docs/assets/js/15ba94aa.e186750d.js +1 -0
  48. solace_agent_mesh/assets/docs/assets/js/15e40e79.434bb30f.js +1 -0
  49. solace_agent_mesh/assets/docs/assets/js/17896441.e612dfb4.js +1 -0
  50. solace_agent_mesh/assets/docs/assets/js/2279.550aa580.js +2 -0
  51. solace_agent_mesh/assets/docs/assets/js/{17896441.a5e82f9b.js.LICENSE.txt → 2279.550aa580.js.LICENSE.txt} +6 -0
  52. solace_agent_mesh/assets/docs/assets/js/240a0364.83e37aa8.js +1 -0
  53. solace_agent_mesh/assets/docs/assets/js/2987107d.a80604f9.js +1 -0
  54. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.2f0db237.js +1 -0
  55. solace_agent_mesh/assets/docs/assets/js/3a6c6137.7e61915d.js +1 -0
  56. solace_agent_mesh/assets/docs/assets/js/3ac1795d.7f7ab1c1.js +1 -0
  57. solace_agent_mesh/assets/docs/assets/js/3ff0015d.e53c9b78.js +1 -0
  58. solace_agent_mesh/assets/docs/assets/js/41adc471.0e95b87c.js +1 -0
  59. solace_agent_mesh/assets/docs/assets/js/4667dc50.bf2ad456.js +1 -0
  60. solace_agent_mesh/assets/docs/assets/js/49eed117.493d6f99.js +1 -0
  61. solace_agent_mesh/assets/docs/assets/js/{509e993c.4c7a1a6d.js → 509e993c.a1fbf45a.js} +1 -1
  62. solace_agent_mesh/assets/docs/assets/js/547e15cc.8e6da617.js +1 -0
  63. solace_agent_mesh/assets/docs/assets/js/55b7b518.29d6e75d.js +1 -0
  64. solace_agent_mesh/assets/docs/assets/js/5b8d9c11.d4eb37b8.js +1 -0
  65. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.1ee87753.js +1 -0
  66. solace_agent_mesh/assets/docs/assets/js/60702c0e.a8bdd79b.js +1 -0
  67. solace_agent_mesh/assets/docs/assets/js/631738c7.fa471607.js +1 -0
  68. solace_agent_mesh/assets/docs/assets/js/64195356.09dbd087.js +1 -0
  69. solace_agent_mesh/assets/docs/assets/js/66d4869e.30340bd3.js +1 -0
  70. solace_agent_mesh/assets/docs/assets/js/6a520c9d.b6e3f2ce.js +1 -0
  71. solace_agent_mesh/assets/docs/assets/js/6aaedf65.7253541d.js +1 -0
  72. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.a5b36a60.js +1 -0
  73. solace_agent_mesh/assets/docs/assets/js/6d84eae0.fd23ba4a.js +1 -0
  74. solace_agent_mesh/assets/docs/assets/js/71da7b71.374b9d54.js +1 -0
  75. solace_agent_mesh/assets/docs/assets/js/729898df.7249e9fd.js +1 -0
  76. solace_agent_mesh/assets/docs/assets/js/7e294c01.7c5f6906.js +1 -0
  77. solace_agent_mesh/assets/docs/assets/js/8024126c.e3467286.js +1 -0
  78. solace_agent_mesh/assets/docs/assets/js/81a99df0.7ed65d45.js +1 -0
  79. solace_agent_mesh/assets/docs/assets/js/82fbfb93.161823a5.js +1 -0
  80. solace_agent_mesh/assets/docs/assets/js/8b032486.91a91afc.js +1 -0
  81. solace_agent_mesh/assets/docs/assets/js/924ffdeb.975e428a.js +1 -0
  82. solace_agent_mesh/assets/docs/assets/js/94e8668d.16083b3f.js +1 -0
  83. solace_agent_mesh/assets/docs/assets/js/9bb13469.4523ae20.js +1 -0
  84. solace_agent_mesh/assets/docs/assets/js/a7d42657.a956689d.js +1 -0
  85. solace_agent_mesh/assets/docs/assets/js/a94703ab.3e5fbcb3.js +1 -0
  86. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e563275.js +1 -0
  87. solace_agent_mesh/assets/docs/assets/js/ad87452a.9d73dad6.js +1 -0
  88. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.0e0d8baf.js +1 -0
  89. solace_agent_mesh/assets/docs/assets/js/cab03b5b.6a073091.js +1 -0
  90. solace_agent_mesh/assets/docs/assets/js/cbe2e9ea.07e170dd.js +1 -0
  91. solace_agent_mesh/assets/docs/assets/js/da0b5bad.b62f7b08.js +1 -0
  92. solace_agent_mesh/assets/docs/assets/js/dd817ffc.c37a755e.js +1 -0
  93. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.b682e9c2.js +1 -0
  94. solace_agent_mesh/assets/docs/assets/js/de915948.44a432bc.js +1 -0
  95. solace_agent_mesh/assets/docs/assets/js/e04b235d.06d23db6.js +1 -0
  96. solace_agent_mesh/assets/docs/assets/js/e1b6eeb4.deb2b62e.js +1 -0
  97. solace_agent_mesh/assets/docs/assets/js/e3d9abda.1476f570.js +1 -0
  98. solace_agent_mesh/assets/docs/assets/js/e6f9706b.acc800d3.js +1 -0
  99. solace_agent_mesh/assets/docs/assets/js/e92d0134.c147a429.js +1 -0
  100. solace_agent_mesh/assets/docs/assets/js/ee0c2fe7.94d0a351.js +1 -0
  101. solace_agent_mesh/assets/docs/assets/js/f284c35a.cc97854c.js +1 -0
  102. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.74710fc1.js +1 -0
  103. solace_agent_mesh/assets/docs/assets/js/main.d634009f.js +2 -0
  104. solace_agent_mesh/assets/docs/assets/js/runtime~main.27bb82a7.js +1 -0
  105. solace_agent_mesh/assets/docs/docs/documentation/components/agents/index.html +68 -68
  106. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/artifact-management/index.html +50 -50
  107. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/audio-tools/index.html +42 -42
  108. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/data-analysis-tools/index.html +55 -55
  109. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/embeds/index.html +82 -68
  110. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/image-tools/index.html +81 -0
  111. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/index.html +67 -50
  112. solace_agent_mesh/assets/docs/docs/documentation/components/builtin-tools/research-tools/index.html +136 -0
  113. solace_agent_mesh/assets/docs/docs/documentation/components/cli/index.html +178 -144
  114. solace_agent_mesh/assets/docs/docs/documentation/components/gateways/index.html +43 -42
  115. solace_agent_mesh/assets/docs/docs/documentation/components/index.html +20 -18
  116. solace_agent_mesh/assets/docs/docs/documentation/components/orchestrator/index.html +23 -23
  117. solace_agent_mesh/assets/docs/docs/documentation/components/platform-service/index.html +33 -0
  118. solace_agent_mesh/assets/docs/docs/documentation/components/plugins/index.html +45 -45
  119. solace_agent_mesh/assets/docs/docs/documentation/components/projects/index.html +182 -0
  120. solace_agent_mesh/assets/docs/docs/documentation/components/prompts/index.html +147 -0
  121. solace_agent_mesh/assets/docs/docs/documentation/components/proxies/index.html +208 -125
  122. solace_agent_mesh/assets/docs/docs/documentation/components/speech/index.html +52 -0
  123. solace_agent_mesh/assets/docs/docs/documentation/deploying/debugging/index.html +28 -49
  124. solace_agent_mesh/assets/docs/docs/documentation/deploying/deployment-options/index.html +29 -30
  125. solace_agent_mesh/assets/docs/docs/documentation/deploying/index.html +14 -14
  126. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/index.html +47 -0
  127. solace_agent_mesh/assets/docs/docs/documentation/deploying/kubernetes/kubernetes-deployment-guide/index.html +197 -0
  128. solace_agent_mesh/assets/docs/docs/documentation/deploying/logging/index.html +90 -0
  129. solace_agent_mesh/assets/docs/docs/documentation/deploying/observability/index.html +17 -16
  130. solace_agent_mesh/assets/docs/docs/documentation/deploying/proxy_configuration/index.html +49 -0
  131. solace_agent_mesh/assets/docs/docs/documentation/developing/create-agents/index.html +38 -38
  132. solace_agent_mesh/assets/docs/docs/documentation/developing/create-gateways/index.html +162 -171
  133. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-python-tools/index.html +67 -49
  134. solace_agent_mesh/assets/docs/docs/documentation/developing/creating-service-providers/index.html +17 -17
  135. solace_agent_mesh/assets/docs/docs/documentation/developing/evaluations/index.html +51 -51
  136. solace_agent_mesh/assets/docs/docs/documentation/developing/index.html +22 -22
  137. solace_agent_mesh/assets/docs/docs/documentation/developing/structure/index.html +27 -27
  138. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/bedrock-agents/index.html +135 -135
  139. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/custom-agent/index.html +66 -66
  140. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/event-mesh-gateway/index.html +51 -51
  141. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mcp-integration/index.html +50 -38
  142. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/mongodb-integration/index.html +86 -86
  143. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rag-integration/index.html +51 -51
  144. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/rest-gateway/index.html +24 -24
  145. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/slack-integration/index.html +30 -30
  146. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/sql-database/index.html +44 -44
  147. solace_agent_mesh/assets/docs/docs/documentation/developing/tutorials/teams-integration/index.html +115 -0
  148. solace_agent_mesh/assets/docs/docs/documentation/enterprise/agent-builder/index.html +86 -0
  149. solace_agent_mesh/assets/docs/docs/documentation/enterprise/connectors/index.html +67 -0
  150. solace_agent_mesh/assets/docs/docs/documentation/enterprise/index.html +23 -19
  151. solace_agent_mesh/assets/docs/docs/documentation/enterprise/installation/index.html +40 -37
  152. solace_agent_mesh/assets/docs/docs/documentation/enterprise/openapi-tools/index.html +324 -0
  153. solace_agent_mesh/assets/docs/docs/documentation/enterprise/rbac-setup-guide/index.html +112 -87
  154. solace_agent_mesh/assets/docs/docs/documentation/enterprise/secure-user-delegated-access/index.html +440 -0
  155. solace_agent_mesh/assets/docs/docs/documentation/enterprise/single-sign-on/index.html +87 -64
  156. solace_agent_mesh/assets/docs/docs/documentation/enterprise/wheel-installation/index.html +62 -0
  157. solace_agent_mesh/assets/docs/docs/documentation/getting-started/architecture/index.html +44 -44
  158. solace_agent_mesh/assets/docs/docs/documentation/getting-started/index.html +39 -37
  159. solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +30 -30
  160. solace_agent_mesh/assets/docs/docs/documentation/getting-started/try-agent-mesh/index.html +18 -18
  161. solace_agent_mesh/assets/docs/docs/documentation/getting-started/vibe_coding/index.html +62 -0
  162. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/artifact-storage/index.html +311 -0
  163. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/configurations/index.html +39 -42
  164. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/index.html +14 -14
  165. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/installation/index.html +27 -25
  166. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/large_language_models/index.html +69 -69
  167. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/run-project/index.html +72 -72
  168. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/session-storage/index.html +251 -0
  169. solace_agent_mesh/assets/docs/docs/documentation/installing-and-configuring/user-feedback/index.html +88 -0
  170. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-gateway-upgrade-to-0.3.0/index.html +42 -42
  171. solace_agent_mesh/assets/docs/docs/documentation/migrations/a2a-upgrade/a2a-technical-migration-map/index.html +20 -20
  172. solace_agent_mesh/assets/docs/docs/documentation/migrations/platform-service-split/index.html +85 -0
  173. solace_agent_mesh/assets/docs/lunr-index-1768329217460.json +1 -0
  174. solace_agent_mesh/assets/docs/lunr-index.json +1 -1
  175. solace_agent_mesh/assets/docs/search-doc-1768329217460.json +1 -0
  176. solace_agent_mesh/assets/docs/search-doc.json +1 -1
  177. solace_agent_mesh/assets/docs/sitemap.xml +1 -1
  178. solace_agent_mesh/cli/__init__.py +1 -1
  179. solace_agent_mesh/cli/commands/add_cmd/__init__.py +3 -1
  180. solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +6 -1
  181. solace_agent_mesh/cli/commands/add_cmd/proxy_cmd.py +100 -0
  182. solace_agent_mesh/cli/commands/docs_cmd.py +4 -1
  183. solace_agent_mesh/cli/commands/eval_cmd.py +1 -1
  184. solace_agent_mesh/cli/commands/init_cmd/__init__.py +15 -0
  185. solace_agent_mesh/cli/commands/init_cmd/directory_step.py +1 -1
  186. solace_agent_mesh/cli/commands/init_cmd/env_step.py +30 -3
  187. solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +3 -4
  188. solace_agent_mesh/cli/commands/init_cmd/platform_service_step.py +85 -0
  189. solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +16 -3
  190. solace_agent_mesh/cli/commands/plugin_cmd/add_cmd.py +2 -1
  191. solace_agent_mesh/cli/commands/plugin_cmd/catalog_cmd.py +1 -0
  192. solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +3 -3
  193. solace_agent_mesh/cli/commands/run_cmd.py +64 -49
  194. solace_agent_mesh/cli/commands/tools_cmd.py +315 -0
  195. solace_agent_mesh/cli/main.py +15 -0
  196. solace_agent_mesh/client/webui/frontend/static/assets/{authCallback-BTf6dqwp.js → authCallback-KnKMP_vb.js} +1 -1
  197. solace_agent_mesh/client/webui/frontend/static/assets/client-DpBL2stg.js +25 -0
  198. solace_agent_mesh/client/webui/frontend/static/assets/main-Cd498TV2.js +435 -0
  199. solace_agent_mesh/client/webui/frontend/static/assets/main-rSf8Vu29.css +1 -0
  200. solace_agent_mesh/client/webui/frontend/static/assets/vendor-CGk8Suyh.js +565 -0
  201. solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -3
  202. solace_agent_mesh/client/webui/frontend/static/index.html +4 -4
  203. solace_agent_mesh/client/webui/frontend/static/mockServiceWorker.js +336 -0
  204. solace_agent_mesh/client/webui/frontend/static/ui-version.json +6 -0
  205. solace_agent_mesh/common/a2a/events.py +2 -1
  206. solace_agent_mesh/common/a2a/protocol.py +5 -0
  207. solace_agent_mesh/common/a2a/types.py +2 -1
  208. solace_agent_mesh/common/a2a_spec/schemas/artifact_creation_progress.json +23 -6
  209. solace_agent_mesh/common/a2a_spec/schemas/feedback_event.json +51 -0
  210. solace_agent_mesh/common/agent_registry.py +38 -11
  211. solace_agent_mesh/common/data_parts.py +144 -4
  212. solace_agent_mesh/common/error_handlers.py +83 -0
  213. solace_agent_mesh/common/exceptions.py +24 -0
  214. solace_agent_mesh/common/oauth/__init__.py +17 -0
  215. solace_agent_mesh/common/oauth/oauth_client.py +408 -0
  216. solace_agent_mesh/common/oauth/utils.py +50 -0
  217. solace_agent_mesh/common/rag_dto.py +156 -0
  218. solace_agent_mesh/common/sac/sam_component_base.py +97 -19
  219. solace_agent_mesh/common/sam_events/event_service.py +2 -2
  220. solace_agent_mesh/common/services/employee_service.py +1 -1
  221. solace_agent_mesh/common/utils/embeds/constants.py +1 -0
  222. solace_agent_mesh/common/utils/embeds/converter.py +1 -8
  223. solace_agent_mesh/common/utils/embeds/modifiers.py +4 -28
  224. solace_agent_mesh/common/utils/embeds/resolver.py +152 -31
  225. solace_agent_mesh/common/utils/embeds/types.py +9 -0
  226. solace_agent_mesh/common/utils/log_formatters.py +20 -0
  227. solace_agent_mesh/common/utils/mime_helpers.py +12 -5
  228. solace_agent_mesh/common/utils/pydantic_utils.py +90 -3
  229. solace_agent_mesh/common/utils/rbac_utils.py +69 -0
  230. solace_agent_mesh/common/utils/templates/__init__.py +8 -0
  231. solace_agent_mesh/common/utils/templates/liquid_renderer.py +210 -0
  232. solace_agent_mesh/common/utils/templates/template_resolver.py +161 -0
  233. solace_agent_mesh/config_portal/backend/common.py +12 -0
  234. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-CljP4_mv.js +103 -0
  235. solace_agent_mesh/config_portal/frontend/static/client/assets/{components-Rk0n-9cK.js → components-CaC6hG8d.js} +22 -22
  236. solace_agent_mesh/config_portal/frontend/static/client/assets/{entry.client-mvZjNKiz.js → entry.client-H_TM0YBt.js} +3 -3
  237. solace_agent_mesh/config_portal/frontend/static/client/assets/{index-DzNKzXrc.js → index-CnFykb2v.js} +16 -16
  238. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-f8439d40.js +1 -0
  239. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BIMqslJB.css +1 -0
  240. solace_agent_mesh/config_portal/frontend/static/client/assets/root-mJmTIdIk.js +10 -0
  241. solace_agent_mesh/config_portal/frontend/static/client/index.html +3 -3
  242. solace_agent_mesh/core_a2a/service.py +3 -2
  243. solace_agent_mesh/gateway/adapter/__init__.py +1 -0
  244. solace_agent_mesh/gateway/adapter/base.py +170 -0
  245. solace_agent_mesh/gateway/adapter/types.py +230 -0
  246. solace_agent_mesh/gateway/base/app.py +39 -2
  247. solace_agent_mesh/gateway/base/auth_interface.py +103 -0
  248. solace_agent_mesh/gateway/base/component.py +1027 -151
  249. solace_agent_mesh/gateway/generic/__init__.py +1 -0
  250. solace_agent_mesh/gateway/generic/app.py +50 -0
  251. solace_agent_mesh/gateway/generic/component.py +894 -0
  252. solace_agent_mesh/gateway/http_sse/alembic/env.py +0 -7
  253. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_project_users_table.py +72 -0
  254. solace_agent_mesh/gateway/http_sse/alembic/versions/20251023_add_soft_delete_and_search.py +109 -0
  255. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_default_agent_to_projects.py +26 -0
  256. solace_agent_mesh/gateway/http_sse/alembic/versions/20251024_add_projects_table.py +135 -0
  257. solace_agent_mesh/gateway/http_sse/alembic/versions/20251108_create_prompt_tables_with_sharing.py +154 -0
  258. solace_agent_mesh/gateway/http_sse/alembic/versions/20251115_add_parent_task_id.py +32 -0
  259. solace_agent_mesh/gateway/http_sse/alembic/versions/20251126_add_background_task_fields.py +47 -0
  260. solace_agent_mesh/gateway/http_sse/alembic/versions/20251202_add_versioned_fields_to_prompts.py +52 -0
  261. solace_agent_mesh/gateway/http_sse/alembic.ini +0 -36
  262. solace_agent_mesh/gateway/http_sse/app.py +40 -11
  263. solace_agent_mesh/gateway/http_sse/component.py +285 -160
  264. solace_agent_mesh/gateway/http_sse/dependencies.py +149 -114
  265. solace_agent_mesh/gateway/http_sse/main.py +68 -450
  266. solace_agent_mesh/gateway/http_sse/repository/__init__.py +19 -1
  267. solace_agent_mesh/gateway/http_sse/repository/chat_task_repository.py +2 -2
  268. solace_agent_mesh/gateway/http_sse/repository/entities/project.py +81 -0
  269. solace_agent_mesh/gateway/http_sse/repository/entities/project_user.py +47 -0
  270. solace_agent_mesh/gateway/http_sse/repository/entities/session.py +26 -3
  271. solace_agent_mesh/gateway/http_sse/repository/entities/task.py +7 -0
  272. solace_agent_mesh/gateway/http_sse/repository/feedback_repository.py +47 -0
  273. solace_agent_mesh/gateway/http_sse/repository/interfaces.py +114 -6
  274. solace_agent_mesh/gateway/http_sse/repository/models/__init__.py +13 -0
  275. solace_agent_mesh/gateway/http_sse/repository/models/project_model.py +51 -0
  276. solace_agent_mesh/gateway/http_sse/repository/models/project_user_model.py +75 -0
  277. solace_agent_mesh/gateway/http_sse/repository/models/prompt_model.py +159 -0
  278. solace_agent_mesh/gateway/http_sse/repository/models/session_model.py +8 -2
  279. solace_agent_mesh/gateway/http_sse/repository/models/task_model.py +8 -1
  280. solace_agent_mesh/gateway/http_sse/repository/project_repository.py +172 -0
  281. solace_agent_mesh/gateway/http_sse/repository/project_user_repository.py +186 -0
  282. solace_agent_mesh/gateway/http_sse/repository/session_repository.py +177 -11
  283. solace_agent_mesh/gateway/http_sse/repository/task_repository.py +86 -2
  284. solace_agent_mesh/gateway/http_sse/routers/agent_cards.py +38 -7
  285. solace_agent_mesh/gateway/http_sse/routers/artifacts.py +256 -58
  286. solace_agent_mesh/gateway/http_sse/routers/auth.py +168 -134
  287. solace_agent_mesh/gateway/http_sse/routers/config.py +302 -8
  288. solace_agent_mesh/gateway/http_sse/routers/dto/project_dto.py +69 -0
  289. solace_agent_mesh/gateway/http_sse/routers/dto/prompt_dto.py +255 -0
  290. solace_agent_mesh/gateway/http_sse/routers/dto/requests/project_requests.py +48 -0
  291. solace_agent_mesh/gateway/http_sse/routers/dto/requests/session_requests.py +14 -1
  292. solace_agent_mesh/gateway/http_sse/routers/dto/responses/base_responses.py +1 -1
  293. solace_agent_mesh/gateway/http_sse/routers/dto/responses/project_responses.py +31 -0
  294. solace_agent_mesh/gateway/http_sse/routers/dto/responses/session_responses.py +5 -2
  295. solace_agent_mesh/gateway/http_sse/routers/dto/responses/version_responses.py +31 -0
  296. solace_agent_mesh/gateway/http_sse/routers/feedback.py +133 -2
  297. solace_agent_mesh/gateway/http_sse/routers/people.py +2 -2
  298. solace_agent_mesh/gateway/http_sse/routers/projects.py +768 -0
  299. solace_agent_mesh/gateway/http_sse/routers/prompts.py +1416 -0
  300. solace_agent_mesh/gateway/http_sse/routers/sessions.py +167 -7
  301. solace_agent_mesh/gateway/http_sse/routers/speech.py +355 -0
  302. solace_agent_mesh/gateway/http_sse/routers/sse.py +131 -8
  303. solace_agent_mesh/gateway/http_sse/routers/tasks.py +670 -18
  304. solace_agent_mesh/gateway/http_sse/routers/users.py +1 -1
  305. solace_agent_mesh/gateway/http_sse/routers/version.py +343 -0
  306. solace_agent_mesh/gateway/http_sse/routers/visualization.py +92 -9
  307. solace_agent_mesh/gateway/http_sse/services/audio_service.py +1227 -0
  308. solace_agent_mesh/gateway/http_sse/services/background_task_monitor.py +186 -0
  309. solace_agent_mesh/gateway/http_sse/services/data_retention_service.py +1 -1
  310. solace_agent_mesh/gateway/http_sse/services/feedback_service.py +1 -1
  311. solace_agent_mesh/gateway/http_sse/services/project_service.py +930 -0
  312. solace_agent_mesh/gateway/http_sse/services/prompt_builder_assistant.py +303 -0
  313. solace_agent_mesh/gateway/http_sse/services/session_service.py +361 -12
  314. solace_agent_mesh/gateway/http_sse/services/task_logger_service.py +354 -4
  315. solace_agent_mesh/gateway/http_sse/session_manager.py +15 -15
  316. solace_agent_mesh/gateway/http_sse/sse_manager.py +286 -166
  317. solace_agent_mesh/gateway/http_sse/utils/artifact_copy_utils.py +370 -0
  318. solace_agent_mesh/gateway/http_sse/utils/stim_utils.py +41 -1
  319. solace_agent_mesh/services/__init__.py +0 -0
  320. solace_agent_mesh/services/platform/__init__.py +29 -0
  321. solace_agent_mesh/services/platform/alembic/env.py +85 -0
  322. solace_agent_mesh/services/platform/alembic/script.py.mako +28 -0
  323. solace_agent_mesh/services/platform/alembic.ini +109 -0
  324. solace_agent_mesh/services/platform/api/__init__.py +3 -0
  325. solace_agent_mesh/services/platform/api/dependencies.py +154 -0
  326. solace_agent_mesh/services/platform/api/main.py +314 -0
  327. solace_agent_mesh/services/platform/api/middleware.py +51 -0
  328. solace_agent_mesh/services/platform/api/routers/__init__.py +33 -0
  329. solace_agent_mesh/services/platform/api/routers/health_router.py +31 -0
  330. solace_agent_mesh/services/platform/app.py +215 -0
  331. solace_agent_mesh/services/platform/component.py +777 -0
  332. solace_agent_mesh/shared/__init__.py +14 -0
  333. solace_agent_mesh/shared/api/__init__.py +42 -0
  334. solace_agent_mesh/shared/auth/__init__.py +26 -0
  335. solace_agent_mesh/shared/auth/dependencies.py +204 -0
  336. solace_agent_mesh/shared/auth/middleware.py +347 -0
  337. solace_agent_mesh/shared/database/__init__.py +20 -0
  338. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/base_repository.py +1 -1
  339. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_exceptions.py +1 -1
  340. solace_agent_mesh/{gateway/http_sse/shared → shared/database}/database_helpers.py +1 -1
  341. solace_agent_mesh/shared/exceptions/__init__.py +36 -0
  342. solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exception_handlers.py +19 -5
  343. solace_agent_mesh/shared/utils/__init__.py +21 -0
  344. solace_agent_mesh/templates/logging_config_template.yaml +48 -0
  345. solace_agent_mesh/templates/main_orchestrator.yaml +12 -1
  346. solace_agent_mesh/templates/platform.yaml +49 -0
  347. solace_agent_mesh/templates/plugin_readme_template.md +3 -25
  348. solace_agent_mesh/templates/plugin_tool_config_template.yaml +109 -0
  349. solace_agent_mesh/templates/proxy_template.yaml +62 -0
  350. solace_agent_mesh/templates/webui.yaml +148 -6
  351. solace_agent_mesh/tools/web_search/__init__.py +18 -0
  352. solace_agent_mesh/tools/web_search/base.py +84 -0
  353. solace_agent_mesh/tools/web_search/google_search.py +247 -0
  354. solace_agent_mesh/tools/web_search/models.py +99 -0
  355. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/METADATA +31 -12
  356. solace_agent_mesh-1.13.2.dist-info/RECORD +591 -0
  357. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/WHEEL +1 -1
  358. solace_agent_mesh/agent/adk/adk_llm.txt +0 -232
  359. solace_agent_mesh/agent/adk/adk_llm_detail.txt +0 -566
  360. solace_agent_mesh/agent/adk/artifacts/artifacts_llm.txt +0 -171
  361. solace_agent_mesh/agent/adk/models/models_llm.txt +0 -142
  362. solace_agent_mesh/agent/agent_llm.txt +0 -378
  363. solace_agent_mesh/agent/agent_llm_detail.txt +0 -1702
  364. solace_agent_mesh/agent/protocol/protocol_llm.txt +0 -81
  365. solace_agent_mesh/agent/protocol/protocol_llm_detail.txt +0 -92
  366. solace_agent_mesh/agent/sac/sac_llm.txt +0 -189
  367. solace_agent_mesh/agent/sac/sac_llm_detail.txt +0 -200
  368. solace_agent_mesh/agent/testing/testing_llm.txt +0 -57
  369. solace_agent_mesh/agent/testing/testing_llm_detail.txt +0 -68
  370. solace_agent_mesh/agent/tools/tools_llm.txt +0 -263
  371. solace_agent_mesh/agent/tools/tools_llm_detail.txt +0 -274
  372. solace_agent_mesh/agent/utils/utils_llm.txt +0 -138
  373. solace_agent_mesh/agent/utils/utils_llm_detail.txt +0 -149
  374. solace_agent_mesh/assets/docs/assets/js/15ba94aa.932dd2db.js +0 -1
  375. solace_agent_mesh/assets/docs/assets/js/17896441.a5e82f9b.js +0 -2
  376. solace_agent_mesh/assets/docs/assets/js/240a0364.7eac6021.js +0 -1
  377. solace_agent_mesh/assets/docs/assets/js/2e32b5e0.33f5d75b.js +0 -1
  378. solace_agent_mesh/assets/docs/assets/js/3a6c6137.f5940cfa.js +0 -1
  379. solace_agent_mesh/assets/docs/assets/js/3ac1795d.76654dd9.js +0 -1
  380. solace_agent_mesh/assets/docs/assets/js/3ff0015d.2be20244.js +0 -1
  381. solace_agent_mesh/assets/docs/assets/js/547e15cc.2cbb060a.js +0 -1
  382. solace_agent_mesh/assets/docs/assets/js/55b7b518.f2b1d1ba.js +0 -1
  383. solace_agent_mesh/assets/docs/assets/js/5c2bd65f.eda4bcb2.js +0 -1
  384. solace_agent_mesh/assets/docs/assets/js/631738c7.a8b1ef8b.js +0 -1
  385. solace_agent_mesh/assets/docs/assets/js/6a520c9d.ba015d81.js +0 -1
  386. solace_agent_mesh/assets/docs/assets/js/6ad8f0bd.f4b15f3b.js +0 -1
  387. solace_agent_mesh/assets/docs/assets/js/6d84eae0.4a5fbf39.js +0 -1
  388. solace_agent_mesh/assets/docs/assets/js/71da7b71.38583438.js +0 -1
  389. solace_agent_mesh/assets/docs/assets/js/8024126c.56e59919.js +0 -1
  390. solace_agent_mesh/assets/docs/assets/js/81a99df0.07034dd9.js +0 -1
  391. solace_agent_mesh/assets/docs/assets/js/82fbfb93.139a1a1f.js +0 -1
  392. solace_agent_mesh/assets/docs/assets/js/924ffdeb.8095e148.js +0 -1
  393. solace_agent_mesh/assets/docs/assets/js/94e8668d.b5ddb7a1.js +0 -1
  394. solace_agent_mesh/assets/docs/assets/js/9bb13469.dd1c9b54.js +0 -1
  395. solace_agent_mesh/assets/docs/assets/js/a94703ab.0438dbc2.js +0 -1
  396. solace_agent_mesh/assets/docs/assets/js/ab9708a8.3e6dd091.js +0 -1
  397. solace_agent_mesh/assets/docs/assets/js/c93cbaa0.eaff365e.js +0 -1
  398. solace_agent_mesh/assets/docs/assets/js/da0b5bad.d08a9466.js +0 -1
  399. solace_agent_mesh/assets/docs/assets/js/dd817ffc.0aa9630a.js +0 -1
  400. solace_agent_mesh/assets/docs/assets/js/dd81e2b8.d590bc9e.js +0 -1
  401. solace_agent_mesh/assets/docs/assets/js/de915948.27d6b065.js +0 -1
  402. solace_agent_mesh/assets/docs/assets/js/e3d9abda.6b9493d0.js +0 -1
  403. solace_agent_mesh/assets/docs/assets/js/e6f9706b.e74a984d.js +0 -1
  404. solace_agent_mesh/assets/docs/assets/js/e92d0134.cf6d6522.js +0 -1
  405. solace_agent_mesh/assets/docs/assets/js/f284c35a.42f59cdd.js +0 -1
  406. solace_agent_mesh/assets/docs/assets/js/ff4d71f2.15b02f97.js +0 -1
  407. solace_agent_mesh/assets/docs/assets/js/main.b12eac43.js +0 -2
  408. solace_agent_mesh/assets/docs/assets/js/runtime~main.e268214e.js +0 -1
  409. solace_agent_mesh/assets/docs/lunr-index-1761248203150.json +0 -1
  410. solace_agent_mesh/assets/docs/search-doc-1761248203150.json +0 -1
  411. solace_agent_mesh/cli/commands/add_cmd/add_cmd_llm.txt +0 -250
  412. solace_agent_mesh/cli/commands/init_cmd/init_cmd_llm.txt +0 -365
  413. solace_agent_mesh/cli/commands/plugin_cmd/plugin_cmd_llm.txt +0 -305
  414. solace_agent_mesh/client/webui/frontend/static/assets/client-CaY59VuC.js +0 -25
  415. solace_agent_mesh/client/webui/frontend/static/assets/main-B32noGmR.js +0 -342
  416. solace_agent_mesh/client/webui/frontend/static/assets/main-DHJKSW1S.css +0 -1
  417. solace_agent_mesh/client/webui/frontend/static/assets/vendor-BEmvJSYz.js +0 -405
  418. solace_agent_mesh/common/a2a/a2a_llm.txt +0 -182
  419. solace_agent_mesh/common/a2a/a2a_llm_detail.txt +0 -193
  420. solace_agent_mesh/common/a2a_spec/a2a_spec_llm.txt +0 -407
  421. solace_agent_mesh/common/a2a_spec/a2a_spec_llm_detail.txt +0 -736
  422. solace_agent_mesh/common/a2a_spec/schemas/schemas_llm.txt +0 -313
  423. solace_agent_mesh/common/common_llm.txt +0 -251
  424. solace_agent_mesh/common/common_llm_detail.txt +0 -2562
  425. solace_agent_mesh/common/middleware/middleware_llm.txt +0 -174
  426. solace_agent_mesh/common/middleware/middleware_llm_detail.txt +0 -185
  427. solace_agent_mesh/common/sac/sac_llm.txt +0 -71
  428. solace_agent_mesh/common/sac/sac_llm_detail.txt +0 -82
  429. solace_agent_mesh/common/sam_events/sam_events_llm.txt +0 -104
  430. solace_agent_mesh/common/sam_events/sam_events_llm_detail.txt +0 -115
  431. solace_agent_mesh/common/services/providers/providers_llm.txt +0 -80
  432. solace_agent_mesh/common/services/services_llm.txt +0 -363
  433. solace_agent_mesh/common/services/services_llm_detail.txt +0 -459
  434. solace_agent_mesh/common/utils/embeds/embeds_llm.txt +0 -220
  435. solace_agent_mesh/common/utils/utils_llm.txt +0 -336
  436. solace_agent_mesh/common/utils/utils_llm_detail.txt +0 -572
  437. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-ByU1X1HD.js +0 -98
  438. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-61038fc6.js +0 -1
  439. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BWvk5-gF.js +0 -10
  440. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DxRwaWiE.css +0 -1
  441. solace_agent_mesh/core_a2a/core_a2a_llm.txt +0 -90
  442. solace_agent_mesh/core_a2a/core_a2a_llm_detail.txt +0 -101
  443. solace_agent_mesh/gateway/base/base_llm.txt +0 -224
  444. solace_agent_mesh/gateway/base/base_llm_detail.txt +0 -235
  445. solace_agent_mesh/gateway/gateway_llm.txt +0 -373
  446. solace_agent_mesh/gateway/gateway_llm_detail.txt +0 -3885
  447. solace_agent_mesh/gateway/http_sse/alembic/alembic_llm.txt +0 -295
  448. solace_agent_mesh/gateway/http_sse/alembic/versions/versions_llm.txt +0 -155
  449. solace_agent_mesh/gateway/http_sse/components/components_llm.txt +0 -105
  450. solace_agent_mesh/gateway/http_sse/http_sse_llm.txt +0 -299
  451. solace_agent_mesh/gateway/http_sse/http_sse_llm_detail.txt +0 -3278
  452. solace_agent_mesh/gateway/http_sse/repository/entities/entities_llm.txt +0 -263
  453. solace_agent_mesh/gateway/http_sse/repository/models/models_llm.txt +0 -266
  454. solace_agent_mesh/gateway/http_sse/repository/repository_llm.txt +0 -340
  455. solace_agent_mesh/gateway/http_sse/routers/dto/dto_llm.txt +0 -346
  456. solace_agent_mesh/gateway/http_sse/routers/dto/requests/requests_llm.txt +0 -83
  457. solace_agent_mesh/gateway/http_sse/routers/dto/responses/responses_llm.txt +0 -107
  458. solace_agent_mesh/gateway/http_sse/routers/routers_llm.txt +0 -314
  459. solace_agent_mesh/gateway/http_sse/services/services_llm.txt +0 -297
  460. solace_agent_mesh/gateway/http_sse/shared/__init__.py +0 -146
  461. solace_agent_mesh/gateway/http_sse/shared/shared_llm.txt +0 -285
  462. solace_agent_mesh/gateway/http_sse/utils/utils_llm.txt +0 -47
  463. solace_agent_mesh/llm.txt +0 -228
  464. solace_agent_mesh/llm_detail.txt +0 -2835
  465. solace_agent_mesh/solace_agent_mesh_llm.txt +0 -362
  466. solace_agent_mesh/solace_agent_mesh_llm_detail.txt +0 -8599
  467. solace_agent_mesh/templates/logging_config_template.ini +0 -45
  468. solace_agent_mesh/templates/templates_llm.txt +0 -147
  469. solace_agent_mesh-1.6.1.dist-info/RECORD +0 -525
  470. /solace_agent_mesh/assets/docs/assets/js/{main.b12eac43.js.LICENSE.txt → main.d634009f.js.LICENSE.txt} +0 -0
  471. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/auth_utils.py +0 -0
  472. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/pagination.py +0 -0
  473. /solace_agent_mesh/{gateway/http_sse/shared → shared/api}/response_utils.py +0 -0
  474. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/error_dto.py +0 -0
  475. /solace_agent_mesh/{gateway/http_sse/shared → shared/exceptions}/exceptions.py +0 -0
  476. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/enums.py +0 -0
  477. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/timestamp_utils.py +0 -0
  478. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/types.py +0 -0
  479. /solace_agent_mesh/{gateway/http_sse/shared → shared/utils}/utils.py +0 -0
  480. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/entry_points.txt +0 -0
  481. {solace_agent_mesh-1.6.1.dist-info → solace_agent_mesh-1.13.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,777 @@
1
+ """
2
+ Platform Service Component for Solace Agent Mesh.
3
+ Hosts the FastAPI REST API server for platform configuration management.
4
+ """
5
+
6
+ import logging
7
+ import threading
8
+ import json
9
+ from typing import Any, Dict
10
+
11
+ import uvicorn
12
+ from solace_ai_connector.common.message import Message as SolaceMessage
13
+ from solace_agent_mesh.common.sac.sam_component_base import SamComponentBase
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
22
+
23
+ log = logging.getLogger(__name__)
24
+
25
+
26
+ class _StubSessionManager:
27
+ """
28
+ Minimal stub for SessionManager to satisfy legacy router dependencies.
29
+
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.
33
+ """
34
+ pass
35
+
36
+
37
+ info = {
38
+ "class_name": "PlatformServiceComponent",
39
+ "description": (
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."
43
+ ),
44
+ }
45
+
46
+
47
+ class PlatformServiceComponent(SamComponentBase):
48
+ """
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
62
+
63
+ Key characteristics:
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)
69
+ """
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
+
94
+ def __init__(self, **kwargs):
95
+ """
96
+ Initialize the PlatformServiceComponent.
97
+
98
+ Retrieves configuration, initializes FastAPI server state,
99
+ and starts the FastAPI/Uvicorn server.
100
+ """
101
+ # Initialize SamComponentBase (provides namespace, max_message_size, async loop)
102
+ super().__init__(info, **kwargs)
103
+ log.info("%s Initializing Platform Service Component...", self.log_identifier)
104
+
105
+ # Note: self.namespace is already set by SamComponentBase
106
+ # Note: self.max_message_size_bytes is already set by SamComponentBase
107
+
108
+ try:
109
+ # Retrieve Platform Service specific configuration
110
+ self.database_url = self.get_config("database_url")
111
+ self.fastapi_host = self.get_config("fastapi_host", "127.0.0.1")
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", "")
117
+ self.cors_allowed_origins = self.get_config("cors_allowed_origins", ["*"])
118
+ self.cors_allowed_origin_regex = self.get_config("cors_allowed_origin_regex", "")
119
+
120
+ # OAuth2 configuration (enterprise feature - defaults to community mode)
121
+ self.external_auth_service_url = self.get_config("external_auth_service_url", "")
122
+ self.external_auth_provider = self.get_config("external_auth_provider", "generic")
123
+
124
+ # Background task configuration
125
+ self.deployment_timeout_minutes = self.get_config("deployment_timeout_minutes", 5)
126
+ self.heartbeat_timeout_seconds = self.get_config("heartbeat_timeout_seconds", 90)
127
+ self.deployment_check_interval_seconds = self.get_config("deployment_check_interval_seconds", 60)
128
+
129
+ # Agent health check configuration (for removing expired agents from registry)
130
+ self.health_check_interval_seconds = self.get_config(
131
+ "health_check_interval_seconds", HEALTH_CHECK_INTERVAL_SECONDS
132
+ )
133
+ self.health_check_ttl_seconds = self.get_config(
134
+ "health_check_ttl_seconds", HEALTH_CHECK_TTL_SECONDS
135
+ )
136
+
137
+ log.info(
138
+ "%s Platform service configuration retrieved (Host: %s, Port: %d, Auth: %s).",
139
+ self.log_identifier,
140
+ self.fastapi_host,
141
+ self.fastapi_port,
142
+ "enabled" if self.get_config("frontend_use_authorization", False) else "disabled",
143
+ )
144
+ except Exception as e:
145
+ log.error("%s Failed to retrieve configuration: %s", self.log_identifier, e)
146
+ raise ValueError(f"Configuration retrieval error: {e}") from e
147
+
148
+ # FastAPI server state (initialized later)
149
+ self.fastapi_app = None
150
+ self.uvicorn_server = None
151
+ self.fastapi_thread = None
152
+
153
+ # Config resolver (permissive default - allows all features/scopes)
154
+ self.config_resolver = ConfigResolver()
155
+
156
+ # Legacy router compatibility
157
+ # webui_backend routers were originally designed for WebUI gateway context
158
+ # but now work with Platform Service via dependency abstraction
159
+ self.session_manager = _StubSessionManager()
160
+
161
+ # Agent discovery (like BaseGatewayComponent)
162
+ # Initialize here so CoreA2AService can use it
163
+ from solace_agent_mesh.common.agent_registry import AgentRegistry
164
+ self.agent_registry = AgentRegistry()
165
+ self.core_a2a_service = CoreA2AService(
166
+ agent_registry=self.agent_registry,
167
+ namespace=self.namespace,
168
+ component_id="Platform"
169
+ )
170
+ log.info("%s Agent discovery service initialized", self.log_identifier)
171
+
172
+ # Background task state (for heartbeat monitoring and deployment status checking)
173
+ # Note: agent_registry already initialized above
174
+ self.heartbeat_tracker = None
175
+ self.heartbeat_listener = None
176
+ self.background_scheduler = None
177
+ self.background_tasks_thread = None
178
+
179
+ self.direct_publisher = None
180
+
181
+ log.info("%s Running database migrations...", self.log_identifier)
182
+ self._run_database_migrations()
183
+ log.info("%s Database migrations completed", self.log_identifier)
184
+
185
+ log.info("%s Platform Service Component initialized.", self.log_identifier)
186
+
187
+ def _run_database_migrations(self):
188
+ """Run database migrations synchronously during __init__."""
189
+ try:
190
+ from .api.main import _setup_database
191
+ _setup_database(self.database_url)
192
+ except Exception as e:
193
+ log.error(
194
+ "%s Failed to run database migrations: %s",
195
+ self.log_identifier,
196
+ e,
197
+ exc_info=True
198
+ )
199
+ raise RuntimeError(f"Database migration failed during component initialization: {e}") from e
200
+
201
+ def _late_init(self):
202
+ """
203
+ Late initialization called by SamComponentBase.run() after broker is ready.
204
+
205
+ This is the proper place to initialize services that require broker connectivity:
206
+ - FastAPI server (with startup event for background tasks)
207
+ - Direct message publisher (for deployer commands)
208
+ - Agent health check timer (for removing expired agents from registry)
209
+ """
210
+ log.info("%s Starting late initialization (broker-dependent services)...", self.log_identifier)
211
+
212
+ # Initialize direct message publisher for deployer commands
213
+ self._init_direct_publisher()
214
+
215
+ # Start FastAPI server (background tasks started via FastAPI startup event)
216
+ self._start_fastapi_server()
217
+
218
+ # Schedule agent health checks to remove expired agents from registry
219
+ self._schedule_agent_health_check()
220
+
221
+ log.info("%s Late initialization complete", self.log_identifier)
222
+
223
+ def _start_fastapi_server(self):
224
+ """
225
+ Start the FastAPI/Uvicorn server in a separate background thread.
226
+
227
+ This method:
228
+ 1. Runs enterprise platform migrations if available
229
+ 2. Imports the FastAPI app and setup function
230
+ 3. Calls setup_dependencies to initialize DB, middleware, and routers
231
+ 4. Creates uvicorn.Config and uvicorn.Server
232
+ 5. Starts the server in a daemon thread
233
+ """
234
+ log.info(
235
+ "%s Attempting to start FastAPI/Uvicorn server...",
236
+ self.log_identifier,
237
+ )
238
+
239
+ if self.fastapi_thread and self.fastapi_thread.is_alive():
240
+ log.warning(
241
+ "%s FastAPI server thread already started.", self.log_identifier
242
+ )
243
+ return
244
+
245
+ try:
246
+ # Import FastAPI app and setup function
247
+ from .api.main import app as fastapi_app_instance
248
+ from .api.main import setup_dependencies
249
+
250
+ self.fastapi_app = fastapi_app_instance
251
+
252
+ setup_dependencies(self)
253
+
254
+ # Register startup event for background tasks
255
+ @self.fastapi_app.on_event("startup")
256
+ async def start_background_tasks():
257
+ try:
258
+ from solace_agent_mesh_enterprise.init_enterprise import start_platform_background_tasks
259
+
260
+ log.info("%s Starting enterprise platform background tasks...", self.log_identifier)
261
+ await start_platform_background_tasks(self)
262
+ log.info("%s Enterprise platform background tasks started", self.log_identifier)
263
+ except ImportError:
264
+ log.info(
265
+ "%s Enterprise package not available - no background tasks to start",
266
+ self.log_identifier
267
+ )
268
+ except Exception as e:
269
+ log.error(
270
+ "%s Failed to start enterprise background tasks: %s",
271
+ self.log_identifier,
272
+ e,
273
+ exc_info=True
274
+ )
275
+
276
+ # Determine port based on SSL configuration
277
+ port = (
278
+ self.fastapi_https_port
279
+ if self.ssl_keyfile and self.ssl_certfile
280
+ else self.fastapi_port
281
+ )
282
+
283
+ # Create uvicorn configuration with SSL support
284
+ config = uvicorn.Config(
285
+ app=self.fastapi_app,
286
+ host=self.fastapi_host,
287
+ port=port,
288
+ log_level="warning",
289
+ lifespan="on",
290
+ ssl_keyfile=self.ssl_keyfile if self.ssl_keyfile else None,
291
+ ssl_certfile=self.ssl_certfile if self.ssl_certfile else None,
292
+ ssl_keyfile_password=self.ssl_keyfile_password if self.ssl_keyfile_password else None,
293
+ log_config=None,
294
+ )
295
+ self.uvicorn_server = uvicorn.Server(config)
296
+
297
+ # Start server in background thread
298
+ self.fastapi_thread = threading.Thread(
299
+ target=self.uvicorn_server.run,
300
+ daemon=True,
301
+ name="PlatformService_FastAPI_Thread",
302
+ )
303
+ self.fastapi_thread.start()
304
+
305
+ # Log with correct protocol
306
+ protocol = "https" if self.ssl_keyfile and self.ssl_certfile else "http"
307
+ log.info(
308
+ "%s FastAPI/Uvicorn server starting in background thread on %s://%s:%d",
309
+ self.log_identifier,
310
+ protocol,
311
+ self.fastapi_host,
312
+ port,
313
+ )
314
+
315
+ except Exception as e:
316
+ log.error(
317
+ "%s Failed to start FastAPI/Uvicorn server: %s",
318
+ self.log_identifier,
319
+ e,
320
+ )
321
+ raise
322
+
323
+ def _init_direct_publisher(self):
324
+ """
325
+ Initialize direct message publisher for deployer communication.
326
+
327
+ Platform Service sends deployment commands directly to deployer:
328
+ - {namespace}/deployer/agent/{id}/deploy
329
+ - {namespace}/deployer/agent/{id}/update
330
+ - {namespace}/deployer/agent/{id}/undeploy
331
+
332
+ Uses direct publishing (not A2A protocol) since deployer is a
333
+ standalone service, not an A2A agent.
334
+
335
+ Called from _late_init() and lazily from publish_a2a() if needed.
336
+ Uses SAC's existing broker connection via the BrokerOutput component.
337
+ """
338
+ try:
339
+ main_app = self.get_app()
340
+ if not main_app or not main_app.flows:
341
+ log.info(
342
+ "%s App flows not yet available - direct publisher will be initialized later",
343
+ self.log_identifier
344
+ )
345
+ return
346
+
347
+ # Find BrokerOutput component in the flow (same pattern as App.send_message)
348
+ broker_output = None
349
+ flow = main_app.flows[0]
350
+ if flow.component_groups:
351
+ for group in reversed(flow.component_groups):
352
+ if group:
353
+ comp = group[0]
354
+ if comp.module_info.get("class_name") == "BrokerOutput":
355
+ broker_output = comp
356
+ break
357
+
358
+ if not broker_output or not hasattr(broker_output, 'messaging_service'):
359
+ log.info(
360
+ "%s BrokerOutput component not ready - direct publisher will be initialized later",
361
+ self.log_identifier
362
+ )
363
+ return
364
+
365
+ self._messaging_service = broker_output.messaging_service.messaging_service
366
+ self.direct_publisher = self._messaging_service.create_direct_message_publisher_builder().build()
367
+ self.direct_publisher.start()
368
+
369
+ log.info("%s Direct message publisher initialized for deployer commands", self.log_identifier)
370
+
371
+ except Exception as e:
372
+ log.warning(
373
+ "%s Could not initialize direct publisher: %s (deployment commands will not work)",
374
+ self.log_identifier,
375
+ e
376
+ )
377
+
378
+ async def _handle_message_async(self, message, topic: str) -> None:
379
+ """
380
+ Handle incoming broker messages asynchronously (required by SamComponentBase).
381
+
382
+ Processes agent discovery messages and updates AgentRegistry.
383
+
384
+ Args:
385
+ message: The broker message
386
+ topic: The topic the message was received on
387
+ """
388
+ log.debug(
389
+ "%s Received async message on topic: %s",
390
+ self.log_identifier,
391
+ topic,
392
+ )
393
+
394
+ processed_successfully = False
395
+
396
+ try:
397
+ if a2a.topic_matches_subscription(
398
+ topic, a2a.get_discovery_topic(self.namespace)
399
+ ):
400
+ payload = message.get_payload()
401
+
402
+ # Parse JSON if payload is string/bytes (defensive coding)
403
+ if isinstance(payload, bytes):
404
+ payload = json.loads(payload.decode('utf-8'))
405
+ elif isinstance(payload, str):
406
+ payload = json.loads(payload)
407
+ # else: payload is already a dict (SAC framework auto-parses)
408
+
409
+ processed_successfully = self._handle_discovery_message(payload)
410
+ else:
411
+ log.debug(
412
+ "%s Ignoring message on non-discovery topic: %s",
413
+ self.log_identifier,
414
+ topic,
415
+ )
416
+ processed_successfully = True
417
+
418
+ except Exception as e:
419
+ log.error(
420
+ "%s Error handling async message on topic %s: %s",
421
+ self.log_identifier,
422
+ topic,
423
+ e,
424
+ exc_info=True
425
+ )
426
+ processed_successfully = False
427
+ finally:
428
+ # Acknowledge message (like BaseGatewayComponent pattern)
429
+ if hasattr(message, 'call_acknowledgements'):
430
+ try:
431
+ if processed_successfully:
432
+ message.call_acknowledgements()
433
+ else:
434
+ message.call_negative_acknowledgements()
435
+ except Exception as ack_error:
436
+ log.warning(
437
+ "%s Error acknowledging message: %s",
438
+ self.log_identifier,
439
+ ack_error
440
+ )
441
+
442
+ def _handle_discovery_message(self, payload: Dict) -> bool:
443
+ """
444
+ Handle incoming agent discovery messages.
445
+
446
+ Follows the same pattern as BaseGatewayComponent for consistency.
447
+
448
+ Args:
449
+ payload: The message payload dictionary
450
+
451
+ Returns:
452
+ True if processed successfully, False otherwise
453
+ """
454
+ try:
455
+ agent_card = AgentCard(**payload)
456
+ self.core_a2a_service.process_discovery_message(agent_card)
457
+ log.debug(
458
+ "%s Processed agent discovery: %s",
459
+ self.log_identifier,
460
+ agent_card.name
461
+ )
462
+ return True
463
+ except Exception as e:
464
+ log.error(
465
+ "%s Failed to process discovery message: %s. Payload: %s",
466
+ self.log_identifier,
467
+ e,
468
+ payload,
469
+ exc_info=True
470
+ )
471
+ return False
472
+
473
+ def _get_component_id(self) -> str:
474
+ """
475
+ Return unique identifier for this component (required by SamComponentBase).
476
+
477
+ Returns:
478
+ Component identifier string
479
+ """
480
+ return "platform_service"
481
+
482
+ def _get_component_type(self) -> str:
483
+ """
484
+ Return component type (required by SamComponentBase).
485
+
486
+ Returns:
487
+ Component type string
488
+ """
489
+ return "service"
490
+
491
+ def _pre_async_cleanup(self) -> None:
492
+ """
493
+ Cleanup before async operations stop (required by SamComponentBase).
494
+
495
+ Platform Service doesn't have async-specific resources to clean up here.
496
+ Main cleanup happens in cleanup() method.
497
+ """
498
+ pass
499
+
500
+ def cleanup(self):
501
+ """
502
+ Gracefully shut down the Platform Service Component.
503
+
504
+ This method:
505
+ 1. Stops direct message publisher
506
+ 2. Stops background tasks (heartbeat listener, deployment checker)
507
+ 3. Stops agent registry
508
+ 4. Signals the uvicorn server to exit
509
+ 5. Waits for the FastAPI thread to finish
510
+ 6. Calls parent cleanup
511
+ """
512
+ log.info("%s Cleaning up Platform Service Component...", self.log_identifier)
513
+
514
+ # Stop direct publisher
515
+ if self.direct_publisher:
516
+ try:
517
+ self.direct_publisher.terminate()
518
+ log.info("%s Direct message publisher stopped", self.log_identifier)
519
+ except Exception as e:
520
+ log.warning("%s Error stopping direct publisher: %s", self.log_identifier, e)
521
+
522
+ # Stop background scheduler
523
+ if self.background_scheduler:
524
+ try:
525
+ import asyncio
526
+ loop = asyncio.new_event_loop()
527
+ asyncio.set_event_loop(loop)
528
+ loop.run_until_complete(self.background_scheduler.stop())
529
+ log.info("%s Background scheduler stopped", self.log_identifier)
530
+ except Exception as e:
531
+ log.warning("%s Error stopping background scheduler: %s", self.log_identifier, e)
532
+
533
+ # Stop heartbeat listener
534
+ if self.heartbeat_listener:
535
+ try:
536
+ self.heartbeat_listener.stop()
537
+ log.info("%s Heartbeat listener stopped", self.log_identifier)
538
+ except Exception as e:
539
+ log.warning("%s Error stopping heartbeat listener: %s", self.log_identifier, e)
540
+
541
+ # Cancel health check timer before clearing registry
542
+ self.cancel_timer(self.HEALTH_CHECK_TIMER_ID)
543
+ log.info("%s Health check timer cancelled", self.log_identifier)
544
+
545
+ # Stop agent registry
546
+ if self.agent_registry:
547
+ try:
548
+ self.agent_registry.clear()
549
+ log.info("%s Agent registry stopped", self.log_identifier)
550
+ except Exception as e:
551
+ log.warning("%s Error stopping agent registry: %s", self.log_identifier, e)
552
+
553
+ # Signal uvicorn to shutdown
554
+ if self.uvicorn_server:
555
+ self.uvicorn_server.should_exit = True
556
+
557
+ # Wait for FastAPI thread to exit
558
+ if self.fastapi_thread and self.fastapi_thread.is_alive():
559
+ log.info(
560
+ "%s Waiting for FastAPI server thread to exit...", self.log_identifier
561
+ )
562
+ self.fastapi_thread.join(timeout=10)
563
+ if self.fastapi_thread.is_alive():
564
+ log.warning(
565
+ "%s FastAPI server thread did not exit gracefully.",
566
+ self.log_identifier,
567
+ )
568
+
569
+ # Call SamComponentBase cleanup (stops async loop and threads)
570
+ super().cleanup()
571
+ log.info("%s Platform Service Component cleanup finished.", self.log_identifier)
572
+
573
+ def get_cors_origins(self) -> list[str]:
574
+ """
575
+ Return the configured CORS allowed origins.
576
+
577
+ Returns:
578
+ List of allowed origin strings.
579
+ """
580
+ return self.cors_allowed_origins
581
+
582
+ def get_cors_origin_regex(self) -> str:
583
+ """
584
+ Return the configured CORS allowed origin regex pattern.
585
+
586
+ Returns:
587
+ Regex pattern string, or empty string if not configured.
588
+ """
589
+ return self.cors_allowed_origin_regex
590
+
591
+ def get_namespace(self) -> str:
592
+ """
593
+ Return the component's namespace.
594
+
595
+ Returns:
596
+ Namespace string.
597
+ """
598
+ return self.namespace
599
+
600
+ def get_config_resolver(self) -> ConfigResolver:
601
+ """
602
+ Return the ConfigResolver instance.
603
+
604
+ The default ConfigResolver is permissive and allows all features/scopes.
605
+ This enables webui_backend routers (which use ValidatedUserConfig) to work
606
+ in platform mode without custom authorization logic.
607
+
608
+ Returns:
609
+ ConfigResolver instance.
610
+ """
611
+ return self.config_resolver
612
+
613
+ def get_session_manager(self) -> _StubSessionManager:
614
+ """
615
+ Return the stub SessionManager.
616
+
617
+ Platform service doesn't have real session management, but returns a
618
+ minimal stub to satisfy gateway dependencies that expect SessionManager.
619
+
620
+ Returns:
621
+ Stub SessionManager instance.
622
+ """
623
+ return self.session_manager
624
+
625
+ def get_heartbeat_tracker(self):
626
+ """
627
+ Return the heartbeat tracker instance.
628
+
629
+ Used by deployer status endpoint to check if deployer is online.
630
+
631
+ Returns:
632
+ HeartbeatTracker instance if initialized, None otherwise.
633
+ """
634
+ return self.heartbeat_tracker
635
+
636
+ def get_agent_registry(self):
637
+ """
638
+ Return the agent registry instance.
639
+
640
+ Used for deployment status monitoring.
641
+
642
+ Returns:
643
+ AgentRegistry instance if initialized, None otherwise.
644
+ """
645
+ return self.agent_registry
646
+
647
+ def _schedule_agent_health_check(self):
648
+ """
649
+ Schedule periodic agent health checks to remove expired agents from registry.
650
+
651
+ This is essential for deployment status checking - when an agent is undeployed,
652
+ the deployment status checker needs to see the agent removed from the registry
653
+ to mark the undeploy as successful.
654
+ """
655
+ if self.health_check_interval_seconds > 0:
656
+ log.info(
657
+ "%s Scheduling agent health check every %d seconds (TTL: %d seconds)",
658
+ self.log_identifier,
659
+ self.health_check_interval_seconds,
660
+ self.health_check_ttl_seconds,
661
+ )
662
+ self.add_timer(
663
+ delay_ms=self.health_check_interval_seconds * 1000,
664
+ timer_id=self.HEALTH_CHECK_TIMER_ID,
665
+ interval_ms=self.health_check_interval_seconds * 1000,
666
+ callback=lambda timer_data: self._check_agent_health(),
667
+ )
668
+ else:
669
+ log.warning(
670
+ "%s Agent health check disabled (interval=%d). "
671
+ "Agents will not be automatically removed from registry when they stop sending heartbeats.",
672
+ self.log_identifier,
673
+ self.health_check_interval_seconds,
674
+ )
675
+
676
+ def _check_agent_health(self):
677
+ """
678
+ Check agent health and remove expired agents from registry.
679
+
680
+ Called periodically by the health check timer. Iterates through all
681
+ registered agents and removes any whose TTL has expired (i.e., they
682
+ haven't sent a heartbeat recently).
683
+ """
684
+ log.debug("%s Performing agent health check...", self.log_identifier)
685
+
686
+ agent_names = self.agent_registry.get_agent_names()
687
+ total_agents = len(agent_names)
688
+ agents_removed = 0
689
+
690
+ for agent_name in agent_names:
691
+ is_expired, time_since_last_seen = self.agent_registry.check_ttl_expired(
692
+ agent_name, self.health_check_ttl_seconds
693
+ )
694
+
695
+ if is_expired:
696
+ log.warning(
697
+ "%s Agent '%s' TTL expired (last seen: %d seconds ago, TTL: %d seconds). Removing from registry.",
698
+ self.log_identifier,
699
+ agent_name,
700
+ time_since_last_seen,
701
+ self.health_check_ttl_seconds,
702
+ )
703
+ self.agent_registry.remove_agent(agent_name)
704
+ agents_removed += 1
705
+
706
+ if agents_removed > 0:
707
+ log.info(
708
+ "%s Agent health check complete: %d/%d agents removed",
709
+ self.log_identifier,
710
+ agents_removed,
711
+ total_agents,
712
+ )
713
+ else:
714
+ log.debug(
715
+ "%s Agent health check complete: %d agents, all healthy",
716
+ self.log_identifier,
717
+ total_agents,
718
+ )
719
+
720
+ def publish_a2a(
721
+ self, topic: str, payload: dict, user_properties: dict | None = None
722
+ ):
723
+ """
724
+ Publish direct message to deployer (not A2A protocol).
725
+
726
+ Platform Service sends deployment commands directly to deployer service.
727
+ This is service-to-service communication, not agent-to-agent protocol.
728
+
729
+ Commands sent to:
730
+ - {namespace}/deployer/agent/{agent_id}/deploy
731
+ - {namespace}/deployer/agent/{agent_id}/update
732
+ - {namespace}/deployer/agent/{agent_id}/undeploy
733
+
734
+ Args:
735
+ topic: Message topic
736
+ payload: Message payload dictionary (will be JSON-serialized)
737
+ user_properties: Optional user properties (not used by deployer)
738
+
739
+ Raises:
740
+ Exception: If publishing fails
741
+ """
742
+ import json
743
+ from solace.messaging.resources.topic import Topic
744
+
745
+ log.debug("%s Publishing deployer command to topic: %s", self.log_identifier, topic)
746
+
747
+ try:
748
+ if not self.direct_publisher:
749
+ self._init_direct_publisher()
750
+ if not self.direct_publisher:
751
+ raise RuntimeError("Direct publisher not initialized")
752
+
753
+ # Serialize payload to JSON and convert to bytearray
754
+ message_body = json.dumps(payload)
755
+ message_bytes = bytearray(message_body.encode("utf-8"))
756
+
757
+ # Publish directly to topic
758
+ self.direct_publisher.publish(
759
+ message=message_bytes,
760
+ destination=Topic.of(topic)
761
+ )
762
+
763
+ log.debug(
764
+ "%s Successfully published deployer command to topic: %s (payload size: %d bytes)",
765
+ self.log_identifier,
766
+ topic,
767
+ len(message_body)
768
+ )
769
+
770
+ except Exception as e:
771
+ log.error(
772
+ "%s Failed to publish deployer command: %s",
773
+ self.log_identifier,
774
+ e,
775
+ exc_info=True
776
+ )
777
+ raise